Compare commits

..

No commits in common. "master" and "v4.4" have entirely different histories.
master ... v4.4

302 changed files with 35863 additions and 255076 deletions

View file

@ -1,114 +0,0 @@
name: Build
permissions:
contents: read
on:
push:
branches: [ "master", "stable" ]
pull_request:
branches: [ "master", "stable" ]
jobs:
build-mac:
runs-on: macos-latest
steps:
- uses: actions/checkout@v5
- run: brew install automake
- run: autoreconf -i
- run: ./configure --enable-warning-as-error
- run: cd raid/test && make all test
- run: make all -j$(sysctl -n hw.ncpu)
- run: make dist check
build-linux:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v5
- run: |
sudo apt-get update
sudo apt-get install -y \
linux-modules-extra-$(uname -r) \
zfsutils-linux
sudo modprobe zfs
zfs version
- run: autoreconf -i
- run: ./configure --enable-warning-as-error
- run: make all -j$(nproc)
- run: make snapcheck_btrfs
- run: make snapcheck_zfs
- run: make distcheck -j$(nproc)
build-arm32:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- run: |
sudo apt-get update
sudo apt-get install -y \
gcc-arm-linux-gnueabihf \
libc6-dev-armhf-cross \
qemu-user
- run: autoreconf -i
- run: |
CC=arm-linux-gnueabihf-gcc \
CFLAGS="-O2 -march=armv7-a -mfpu=neon -mfloat-abi=hard" \
TARGET_RUNNER="qemu-arm -cpu cortex-a15 -L /usr/arm-linux-gnueabihf" \
./configure \
--build="$(./config.guess)" \
--host=arm-linux-gnueabihf \
--enable-warning-as-error
- run: make all -j$(nproc)
- run: |
file snapraid
arm-linux-gnueabihf-readelf -h snapraid
- run: |
qemu-arm \
-cpu cortex-a15 \
-L /usr/arm-linux-gnueabihf \
./snapraid -V
- run: make check SHORTCHECK=1
build-win:
runs-on: windows-latest
defaults:
run:
shell: msys2 {0}
steps:
- uses: actions/checkout@v5
- uses: msys2/setup-msys2@v2
with:
msystem: MINGW64
update: true
install: mingw-w64-x86_64-gcc autoconf automake make
- run: autoreconf -i
- run: ./configure --enable-warning-as-error
- run: make all -j$(nproc)
- run: make snapcheck_ntfs
- run: make dist check
build-freebsd:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: vmactions/freebsd-vm@v1
with:
usesh: true
prepare: |
pkg install -y autoconf automake
run: |
autoreconf -i
./configure --enable-warning-as-error
make all -j$(sysctl -n hw.ncpu)
make dist check
build-musl:
runs-on: ubuntu-latest
container: alpine:latest
steps:
- uses: actions/checkout@v5
- run: |
apk add --no-cache \
autoconf \
automake \
build-base \
git \
linux-headers
- run: autoreconf -i
- run: ./configure --enable-warning-as-error
- run: make all -j$(nproc)
- run: make dist check

View file

@ -1,99 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL Advanced"
on:
push:
branches: [ "master", "stable" ]
pull_request:
branches: [ "master", "stable" ]
jobs:
analyze:
name: Analyze (${{ matrix.language }})
# Runner size impacts CodeQL analysis time. To learn more, please see:
# - https://gh.io/recommended-hardware-resources-for-running-codeql
# - https://gh.io/supported-runners-and-hardware-resources
# - https://gh.io/using-larger-runners (GitHub.com only)
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
permissions:
# required for all workflows
security-events: write
# required to fetch internal or private CodeQL packs
packages: read
# only required for workflows in private repositories
actions: read
contents: read
strategy:
fail-fast: false
matrix:
include:
- language: actions
build-mode: none
- language: c-cpp
build-mode: autobuild
# CodeQL supports the following values keywords for 'language': 'actions', 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'rust', 'swift'
# Use `c-cpp` to analyze code written in C, C++ or both
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Add any setup steps before running the `github/codeql-action/init` action.
# This includes steps like installing compilers or runtimes (`actions/setup-node`
# or others). This is typically only required for manual builds.
# - name: Setup runtime (example)
# uses: actions/setup-example@v1
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
languages: ${{ matrix.language }}
build-mode: ${{ matrix.build-mode }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
# queries: security-extended,security-and-quality
# If the analyze step fails for one of the languages you are analyzing with
# "We were unable to automatically build your code", modify the matrix above
# to set the build mode to "manual" for that language. Then modify this step
# to build your code.
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- name: Run manual build steps
if: matrix.build-mode == 'manual'
shell: bash
run: |
echo 'If you are using a "manual" build mode for one or more of the' \
'languages you are analyzing, replace this with the commands to build' \
'your code, for example:'
echo ' make bootstrap'
echo ' make release'
exit 1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
with:
category: "/language:${{matrix.language}}"

60
.gitignore vendored
View file

@ -1,28 +1,13 @@
# archives # archives
*.zip *.zip
*.tar.gz *.tar.gz
*.tgz
*.txz
*.deb
*.rpm
*.zst
# backups # backups
*~ *~
# logs
*.log
stream*.bin
# upload
makepush.sh
makemount.sh
makeumount.sh
# autotools # autotools
Makefile Makefile
Makefile.in Makefile.in
compile
aclocal.m4 aclocal.m4
autom4te.cache/ autom4te.cache/
config.guess config.guess
@ -35,55 +20,16 @@ configure
install-sh install-sh
missing missing
stamp-h1 stamp-h1
.dirstamp
linux/
windows/
# objects # objects
snapraid
mktest
mkstream
*.exe
*.o *.o
*.gcda
*.gcno
*.gcov
makeslackware.sh
makeslackdist.sh
pkg/snapraid.SlackBuild
pkg/snapraid.info
makedeb.sh
pkg/control
makerpm.sh
pkg/snapraid.spec
makearch.sh
makearchdist.sh
pkg/.PKGINFO
pkg/PKGBUILD
pkg/.SRCINFO
# projects # project
*.dst *.dst
*.epr *.epr
*.geany
session.conf
# AFL
makeafl.sh
afl/
afl_corpus/
# specific # specific
cov/ snapraid
cov_release/
contrib/ contrib/
paper/
kernel/
obj/
bench/
support/
archive/
www/
wiki/
beta/
ftp/

148
AGENTS.md
View file

@ -1,148 +0,0 @@
# SnapRAID Development Guide
This document provides guidance for agentic coding agents working on the SnapRAID codebase.
## Project Structure
### Core Source Files (`cmdline/`)
The CLI is organized into focused C modules:
| Modules | Purpose |
|---|---|
| `main.c`, `snapraid.h` / `snapraid.c` | Program entry points, option parsing, and CLI command dispatch |
| `state.h` / `state.c` | Global state (`snapraid_state`), config file parsing, and content file read/write |
| `elem.h` / `elem.c` | Core data model (files, links, dirs, disks, parity, filters) and filter logic |
| `scan.c`, `import.h` / `import.c` | Multi-threaded directory scanner and file-move hash importer |
| `search.h` / `search.c`, `locate.h` / `locate.c` | Path pattern matching and file lookup / path location commands |
| `io.h` / `io.c` | Parallel read-ahead and write-behind I/O queue management |
| `parity.h` / `parity.c` | Parity file operations supporting split parity files |
| `handle.h` / `handle.c` | File handles abstraction for data disk I/O with POSIX fadvise settings |
| `bw.h` / `bw.c` | Bandwidth token-bucket rate limiter |
| `stream.h` / `stream.c` | Buffered stream abstraction with CRC32 integrity checks |
| `sync.c`, `scrub.c`, `check.c`, `status.c` | CLI commands for core operations (synchronize, integrity scrub, check, health status) |
| `pool.c`, `dup.c`, `list.c`, `touch.c`, `rehash.c` | CLI commands for pooling layouts, finding duplicates, listing files, updating tracking/hashes |
| `device.c`, `dry.c` | Disk device geometry/UUID querying, and dry-run execution simulation |
| `murmur3.c`, `spooky2.c`, `museair.c` (and tests) | Non-cryptographic hash implementations (MurmurHash3, SpookyHash, MuseAir) and tests |
| `support.h` / `support.c`, `app.h` | Locks, logging, thread wrappers, global constants |
| `str.h` / `str.c` | Path/string utilities |
| `memory.h` / `memory.c` | Safe memory allocation and tracking helpers |
| `util.h` / `util.c` | Low-level utilities (CRC32 calculations, numeric formatting, hash helpers) |
| `unixapp.c`, `mingwapp.c` | Platform-specific implementations of system info, process management, and services |
| `thermal.h` / `thermal.c` | Temperature monitoring to prevent hardware overheating |
| `selftest.c`, `speed.c` | Self-test command (`test`) and CPU RAID parity performance benchmark (`-T`) |
| `mktest.c`, `mkstream.c` | Standalone test utility tools for recovery and stream validation |
### OS Abstraction Files (`os/`)
The platform abstraction layer is separated into `os/`. Note that `os/` acts as a library layer, so having unused functions (e.g., platform helper functions not currently invoked by the main CLI application) is expected.
| Module | Purpose |
|--------|---------|
| `os.h` | Core OS-independent interface declarations (syslog, signals, execution, threads, mutexes) |
| `portable.h` | Platform detection macros and compatibility definitions |
| `unix.c/h` | UNIX implementation of OS abstraction layer (fork, exec, signals, thread primitives) |
| `mingw.c/h` | Windows implementation of OS abstraction layer (process creation, registry, thread primitives) |
### Key Data Structures
| Struct | Defined in | Description |
|---|---|---|
| `snapraid_state` | `state.h` | Global program state: all disks, parity levels, filter list, options, hash kind, progress |
| `snapraid_option` | `state.h` | Runtime options (force flags, sort order, IO advise mode, bandwidth limit, etc.) |
| `snapraid_disk` | `elem.h` | One data disk: name, mount dir, device id, UUID, file/link/dir hash tables and lists, parity extent tree |
| `snapraid_file` | `elem.h` | A tracked file: sub-path, size, mtime, inode, block vector |
| `snapraid_block` | `elem.h` | One parity block: state (`BLK/CHG/REP/DELETED/EMPTY`) + hash |
| `snapraid_extent` | `elem.h` | Contiguous run of file blocks mapped to contiguous parity positions |
| `snapraid_filter` | `elem.h` | One include/exclude rule: pattern, root scope, `is_disk`, `is_abs`, `is_dir`, direction |
| `snapraid_parity` | `elem.h` | One parity level: up to `SPLIT_MAX=8` split files, total/free blocks |
| `snapraid_io` | `io.h` | Parallel I/O controller: buffer pool, worker threads for each disk |
| `snapraid_worker` | `io.h` | One I/O thread: reads or writes one disk at a time using a task ring buffer |
### Block States
| Constant | Value | Meaning |
|---|---|---|
| `BLOCK_STATE_EMPTY` | 0 | No file mapped here; parity position is zero-filled |
| `BLOCK_STATE_BLK` | 1 | File block with valid hash and up-to-date parity |
| `BLOCK_STATE_CHG` | 2 | File block changed; hash may be old (pre-sync); parity not yet updated |
| `BLOCK_STATE_REP` | 3 | File block hashed (from copy heuristic); parity not yet updated |
| `BLOCK_STATE_DELETED` | 4 | File deleted; block retains old hash for parity recovery; parity not yet zeroed |
| `BLOCK_STATE_REBUILD` | 5 | File block with valid hash; parity untrusted, rebuild in place without reallocation |
### Crash-Recovery Invariants
SnapRAID is designed to recover from an interruption, including `SIGKILL`, at any point. It achieves this by reading recovery data from multiple snapshots, checking file metadata when reading, and validating data with hashes. Account for this design before treating a non-atomic transition or mixed snapshot lifecycle as an integrity defect.
### Build System
- `configure.ac`: Autoconf script (detects systemd vs BSD init)
- `Makefile.am`: Source file lists, dependencies, install hooks (including rules for generating documentation)
- `uncrustify.cfg`: Code formatting rules for main application source files
- `linux.cfg`: Code formatting rules for `raid/` directory and its subdirectories
- Run `make doc` to regenerate all manual pages (`*.1`) and text manuals (`*.txt`)
- Always use parallel compilation with `make -j$(nproc)` instead of plain `make`
- Create temporary files and directories under `/tmp/snapraid/`.
- Both Linux and Windows builds are out-of-tree in dedicated subdirectories (`linux/` and `windows/`) in the project directory, keeping the root directory clean:
- Linux build:
`mkdir -p linux && (cd linux && ../configure && make -j$(nproc))`
Subsequent Linux rebuilds: `(cd linux && make -j$(nproc))`
- Windows x64 cross-compilation:
`mkdir -p windows && (cd windows && ../configure.windows-x64 && make -j$(nproc))`
Subsequent Windows rebuilds: `(cd windows && make -j$(nproc))`
- The Windows build needs to be tested only when modifying Windows-specific code (e.g., `os/mingw.*`, `cmdline/mingwapp.c`, or Windows-specific `#ifdef` paths)
## Code Style Guidelines
#### Design Simplicity
- **Simplicity First**: Always prefer the simplest and cleanest implementation that fully satisfies the demonstrated requirements. Do not introduce extra state, abstractions, conditions, or defensive handling unless a concrete requirement or verified failure mode needs them. When replacing existing logic, preserve its narrow established semantics instead of broadening it through inferred state from unrelated subsystems.
- **Smallest Necessary Change** Harmless existing behavior or artifacts do not justify refactoring. Always make the smallest change necessary to satisfy the requirement.
#### Code Style
- **Language**: The codebase uses **C99 standard** (not C11/C++)
- **Format**: Enforce via `uncrustify -c uncrustify.cfg --no-backup *.c *.h` (or `uncrustify -c linux.cfg --no-backup *.c *.h` for `raid/` directory and subdirectories)
- **Naming**: Snake_case for functions, UPPER_CASE for macros/constants
- **Indentation**: Tabs for indentation, no alignment (existing codebase style)
- **Comments**: Use `/** ... */` for multiline top comments preceding declarations and `/* ... */` for multiline comments within code. Use `/* first letter lowercase */` for single-line inline notes.
- **Critical Comments**: Always add a comment at non-obvious critical points, especially around data-integrity invariants, crash recovery, fallback behavior, concurrency, and fatal versus best-effort error handling. Explain why the logic is required, not merely what the code does.
- **Headers**: All `.h` files have include guards (`#ifndef NAME_H`)
- **Preferences**: Use 0 instead of NULL and '\0'
- **Preferences**: Use prefix ++variable and --variable instead of postfix variable++ and variable-- where both are equivalent
- **Safety Checks**: Avoid adding safety checks for conditions that never happen
- **Type Casts**: Avoid type casts unless strictly necessary for compilation with -Werror and unavoidable by other mean
- **Stack Over Heap**: Prefer stack-allocated fixed-size buffers over dynamic memory allocation (`malloc`/`free`) whenever the upper bound is small, fixed, and known at compile time.
- **Commit Messages**: Every time a change is done, a single line commit description should be provided for that change
- **Git Commits**: Never commit changes to git.
#### Error Handling & Memory Management
- **Return codes**: `0` means no-error; `< 0` means error; positive for specific results
- **Logging**: Use `log_fatal()`, `log_tag()`, `msg_info()`, `msg_progress()`, `msg_verbose()` from `support.h`
- **Tag Escaping**: When emitting structured tags with `log_tag()`, always wrap file paths, directory paths, link targets, disk names, filter patterns, and arbitrary string fields with `esc_tag()` to prevent colons (e.g., Windows drive letters `C:`), backslashes, or newlines from breaking colon-delimited tag parsing.
- **Allocation**: Always use custom `malloc_nofail()`, `calloc_nofail()`, `nalloc_nofail()`, or `strdup_nofail()` wrappers (which handle OOM by aborting)
- **Path Manipulation**: Never use standard unsafe string functions (`strcpy`, `strcat`, `strcmp`) on paths. Always use the platform-correct, size-bounded wrappers in `support.h` (e.g., `pathcpy()`, `pathcat()`, `pathcmp()`, `pathslash()`).
- **TommyDS Iteration**: For `tommy_list`, iterate using:
`tommy_node* node = list.head; while (node) { void* obj = node->data; ... node = node->next; }`
Or use callback iteration helpers: `tommy_list_foreach()`, `tommy_list_foreach_arg()`, `tommy_hashdyn_foreach()`, etc.
- **Cleanup**: Use `goto` pattern for cleanup in complex functions when appropriate
- **Fatal paths**: Use `exit(EXIT_FAILURE)` for unrecoverable errors; `os_abort()` for internal inconsistencies
- **Exit Code & Logging Invariants**:
- `log_fatal()`: Any invocation of `log_fatal()` represents an unrecoverable failure and must force a non-zero exit code upon termination.
- `log_error()`: Whenever `log_error()` is called with a hardware error (`is_hw(err)`), it must force a non-zero exit code upon termination.
#### Threading
- **Compile-time guard**: `#if HAVE_THREAD` wraps all thread-specific code
- **Mutexes**: Always use the custom `thread_mutex_init/destroy/lock/unlock()` wrappers
- **IO workers**: The `snapraid_io` / `snapraid_worker` infrastructure handles parallel disk I/O via a pool of reader and writer threads
#### Testing Changes
- Never run `make check` because it's too expansive
- Run `./linux/snapraid test` for the regression test
- The `test` and `selftest` suites (in `cmdline/selftest.c` and `./linux/snapraid test`) must be strictly memory-only without creating files or performing filesystem I/O
- If running the speed benchmark (`./linux/snapraid -T`), always use `--speed-test-period 100` (e.g. `./linux/snapraid -T --speed-test-period 100`) to run it faster
- The Windows build needs to be tested only when modifying Windows-specific code
- Verify error paths and recovery scenarios (the test suite covers aborted sync, UUID changes, disk failures)

12
AUTHORS
View file

@ -5,19 +5,17 @@ The author of SnapRAID is Andrea Mazzoleni.
You can contact me sending an email at: You can contact me sending an email at:
amadvance@gmail.com amadvance@users.sourceforge.net
Please don't send support requests at this address, but use the SnapRAID
forum.
ACKNOWLEDGMENTS ACKNOWLEDGMENTS
=============== ===============
Special thanks to Leifi, the king of the Forum! A special thanks for the testing, suggestions and bug reports to klbl,
jwill42, tholiin, uhclem, reardonia and the whole SnapRAID Forum.
Thanks for the testing, suggestions and bug reports to klbl, jwill42, tholiin, Thanks to Maxim Tikhonov for making the Ubuntu packages.
uhclem, reardonia, Jens, rubylaser and the whole SnapRAID Forum.
Also thanks for the support to Ben_in_COSprings, Darin, micksh, RamanRB and Also thanks for the support to Ben_in_COSprings, Darin, micksh, RamanRB and
the whole AVS Forum. the whole AVS Forum.

104
BLUEBOX
View file

@ -1,104 +0,0 @@
SnapRAID Windows Smart Screen (Blue Box)
========================================
Windows uses a cloud-based reputation system to vet software. Because
SnapRAID is a specialized Open Source project, it may not have the
"global reputation" required to pass these automated checks silently.
Consequently, when running SnapRAID or the SnapRAID Daemon, Windows
SmartScreen may display a warning dialog (informally called a "Blue
Box") or block execution entirely due to "Malicious binary reputation".
Only expensive EV (Extended Validation) certificates can automatically
bypass these reputation filters, making them generally unsuitable for
free Open Source projects.
OPTION 1: THE "RUN ANYWAY" METHOD
---------------------------------
When the SmartScreen dialog first appears, click "More info" and then
select "Run anyway" to proceed.
This dialog only appears for files downloaded from the internet.
If Windows is blocking the file silently (e.g. you see an "Application
Control policy" error rather than a dialog), skip to Option 2 or 3.
"Run anyway" bypasses the check for that launch only. The prompt may
reappear after the file is updated or replaced.
OPTION 2: PERMANENTLY UNBLOCKING THE FILE
-----------------------------------------
If you would prefer to permanently "unblock" a specific file on your
machine and prevent the prompt from appearing again, follow these steps:
1. Right-click the executable or installer file (.exe) and select
Properties.
2. Stay on the General tab (the default view).
3. Look for the Security section at the very bottom of the window.
4. Check the box labeled Unblock.
5. Click Apply and then OK.
Once unblocked, the file is treated as safe by your local system.
This method removes the Mark of the Web flag that Windows applies to
downloaded files. It is effective against SmartScreen prompts but
will not help on managed machines where an Application Control policy
(WDAC or AppLocker) is enforced by an administrator. If you do not see
an Unblock checkbox, or the block persists after applying it, see the
note at the end of this document.
OPTION 3: ADDING A PATH EXCLUSION (RECOMMENDED FOR RECURRING BLOCKS)
--------------------------------------------------------------------
If Windows continues to block files within your SnapRAID folder, you
can add a permanent folder exclusion to Microsoft Defender. Substitute
the path below for wherever you keep your SnapRAID binaries (e.g.
C:\snapraid).
1. Open Windows Security by searching for it in the Start menu.
2. Select Virus & threat protection.
3. Under "Virus & threat protection settings," click Manage settings.
4. Scroll down to the bottom and click Add or remove exclusions.
5. Click + Add an exclusion and select Folder.
6. Browse to and select your SnapRAID folder (e.g. C:\snapraid).
7. Click Select Folder and confirm any administrator prompts.
By excluding this path, Microsoft Defender will no longer subject files
inside that folder to reputation-based blocks or SmartScreen warnings.
This exclusion applies to Microsoft Defender Antivirus. It does not
override Application Control policies (WDAC or AppLocker) enforced by
an administrator. If blocks persist after adding the exclusion, see the
note below.
Only use this method if you are certain that you only place authentic
SnapRAID files in that directory.
MANAGED OR CORPORATE MACHINES
-----------------------------
If none of the above options resolve the issue, your machine is likely
subject to an Application Control policy enforced by your organisation's
IT department. These policies (implemented via Windows Defender
Application Control or AppLocker) operate at the kernel level and
cannot be overridden by end users.
In this situation you will need to contact your IT administrator and
ask them to whitelist the SnapRAID executable, either by file path, or
by file hash. Providing them with the official download URL
(https://www.snapraid.it) and the file hash may help them process the
request.

30
CHECK
View file

@ -1,30 +0,0 @@
SnapRAID CHECK
==============
The regression test for SnapRAID is run using the command:
make check
You can also run the regression test with Valgrind using:
./configure --enable-valgrind
make check
To perform a coverage test, use the following commands:
./configure --enable-coverage
make lcov_reset
make check
make lcov_capture
make lcov_html
Then, open the file `./cov/index.html` in your browser to view the results.
Note that the coverage analysis excludes error-handling code that causes
immediate program termination. This excluded code is enclosed between the
LCOV_EXCL_START and LCOV_EXCL_STOP keywords.
To test with the Clang static analyzer, use:
scan-build ./configure
scan-build make

248
CHECKSUMS
View file

@ -1,248 +0,0 @@
sha256
761eaf08937139a89d79d1ffbad42508f270d3aa603eac50475f7449ae278dcf snapraid-1.2.tar.gz
10e64f2629eb469a32eabc84e1f9a59593cbbf61282ead964b622af1ec0c4681 snapraid-1.2-windows-x64.zip
27da3c54fe408ab53c6e2b4b398ae46328a2dbc701b785a55bf76ffed6046eb2 snapraid-1.2-windows-x86.zip
2e6aaa660a5a74665044ead40959006632dcd1ee1e21091e6260f5b845304f96 snapraid-1.3.tar.gz
0d0cefeabf8230b66414a8731ceb52a0adaaedb5be0fa11d07a6be44e9f2fb6d snapraid-1.3-windows-x64.zip
4358802fb022ba5e2f8d1323ce963155adccea99069abd5f901eadf1411b6366 snapraid-1.3-windows-x86.zip
157b0ca7cfa9cba43cf995b4c32b0b206e299f5ffff58062069bb6ec41c77c0d snapraid-1.4.tar.gz
5b210dd4667369799fd02757e8efc4d733c704cfe72319d297d4ab969b80c962 snapraid-1.4-windows-x64.zip
77047e1fa1bfcb12db7d5c3167e7dbbbb1718909f1003fd185cdf219cd952427 snapraid-1.4-windows-x86.zip
f460bf9aee4b02b6c08f19b0caa2928b075c73ca4cfc41c7f426f015f67cffbc snapraid-1.5.tar.gz
d19262bdf9e572fa80285887886a8fbe9a7b9bd4159496f112d383bf9b4db797 snapraid-1.5-windows-x64.zip
28816c0cde4cf8ce8e91a585eb9aab5552344a331237b6a2afd50396685814fd snapraid-1.5-windows-x86.zip
e0684d036cfd6b9fcdf23792c057fec4f4531d25aab7c677ff35e7a8be07b098 snapraid-1.6.tar.gz
9c13f99d67aafe43f5c540d97d0f6b40289856f547b8f33ee8aee27b270a7fae snapraid-1.6-windows-x64.zip
ae94db99a06068e17134ce69009492c4bfd8f6e54ea1848df105bb89f9f7ba28 snapraid-1.6-windows-x86.zip
1cf7a8f58533d6bc717ff6d396114ec4ed61eb66ff2756370e4cc730ee4edc4d snapraid-1.7.tar.gz
0cb49c676f3f9fd1f0fc938513b6dcaaf15390b64098e17cff5066667e4d01d5 snapraid-1.7-windows-x64.zip
44bc6b947ba845a89ecf812b82e751dca2dd4a6143ff06391c3b8b285a7ed3a2 snapraid-1.7-windows-x86.zip
da1c09f0139e683c03942c2b9489c2d9b989c59d147f7c28258c8e58c3938037 snapraid-1.8.tar.gz
fca7352fece5d7243af45ba8c5a07e08cc0e24d226468a619b9d86a3767e7099 snapraid-1.8-windows-x64.zip
35520cab33b3b3f9efc4ba4d7a968a7d7d49637b5e256921e0091424f5dd60ee snapraid-1.8-windows-x86.zip
504c3fe288b66c84bc65173979e7cede06370ca2a5f02ef3ca200c2fc8b09ea9 snapraid-1.9.tar.gz
ddba596451a05c61b20ce1e82c8039ba3c13be67b7469f2c75c6b0b7b4b18356 snapraid-1.9-windows-x64.zip
5a0dd3cdc0edf69cd03d926b594e41f5ca7e07564ef1cb3d6ac417c76f16b77b snapraid-1.9-windows-x86.zip
5e4eee49748faf966ebcc1cb3b9127ad7047542baf8952c6e0a9cbb32dac4d88 snapraid-1.10.tar.gz
7812a37f8767beb9542def762b2e131caafffc1b1b21f1d9422030e93e367f12 snapraid-1.10-windows-x64.zip
b899784498050c5d41752464bd31cec7de9e77ec865f55e2192fea75f52787d5 snapraid-1.10-windows-x86.zip
c349c4c25e3cb794d908dc75422ca9b04b44162c295b41d4ea55081af1a3451f snapraid-1.11.tar.gz
47e8f09f3d012d0a34d71e6ece7b9171c82af27766cca709fc9bbd104328cc7d snapraid-1.11-windows-x64.zip
8a8b0562192732022ae1732f5ae48e5f8745e217f73683123b2822e316918204 snapraid-1.11-windows-x86.zip
bd89ef0ddc3909c50fecc30da1d5d70342b92952b5d3ae0a2e31a66c8755dc8a snapraid-1.12.tar.gz
290c5ac8667ca7ada12a0d550e06c9fbc5f4e29abb5af0ef105eba38fb274c5d snapraid-1.12-windows-x64.zip
8cbc4e447f2152c3e76025cdbad03c54e7c85e004bb535f9dc7dde9b86605fe8 snapraid-1.12-windows-x86.zip
7c824abf6cacd8b847467916a1b4c28f48161e4b9f9b6c2f607c4de473a663c9 snapraid-1.13.tar.gz
22f6e9bf1dff5df4abff29b7cf364dc029959991dc158257f2a283721581abf4 snapraid-1.13-windows-x64.zip
9801b1a0331c461ce70c7824e2624dd2866358d61d923ff854253f340985947e snapraid-1.13-windows-x86.zip
68a48c961fcc15ffcfb86e4c5ea2371d562252e61f58fe87a529f479e81fb2bb snapraid-2.0.tar.gz
a2e1fb0610c8bfc57d73da1dbd276c238a032bf9b4c73a41977fcc57e773fff4 snapraid-2.0-windows-x64.zip
0fc3bee4d107bcd5e55a1c5bb81015558d9791d66a44f9ae2e3723906c3199df snapraid-2.0-windows-x86.zip
788377f579486c2b16548563a3d25f385594ae4276f1328c8f82cd0d5e0af9b6 snapraid-2.1.tar.gz
6e32fc0603136c4d3ad60fc1f04e6c919b7e7159267750ebf0dd8ad20ee6b442 snapraid-2.1-windows-x64.zip
d2813aec37f96506bcf98f2b5196204f065786731a5874f495f18f58fe87064b snapraid-2.1-windows-x86.zip
faf9545f0a66865e754ad587731483becf895a954c22e023501a2f28af44682a snapraid-2.2.tar.gz
2ea4b610c8d99f3766f6d2c89be5eafd1e16a17454d9df02d982fa184b517744 snapraid-2.2-windows-x64.zip
e2dac0663546f06ac3e679a93ba5de9e7de91563e09c1396fd367c5b16e011be snapraid-2.2-windows-x86.zip
68e610d67087c02715289934472c5fa3d7aa77c8085298ba54f02f26f7d396ad snapraid-3.0.tar.gz
ca7943f270a940554ddbd8c09698228120da2bac5b6d78486a34f5b301e24f47 snapraid-3.0-windows-x64.zip
c6a47d8bf544e69d9b301fe525d193c8faa8ef056c78f8a0649637d2e99b93c6 snapraid-3.0-windows-x86.zip
b5b22350c221e145c3347426f186f188f5d64616d03f196b35d75db564e78f7f snapraid-3.1.tar.gz
6d275cf3d579a5050e936879db85acbcb34b6522b36d5bc81b2f3764ca011c87 snapraid-3.1-windows-x64.zip
66f5967e559368193aef7b13a1c641694ca62f64e4b5749a7e2709aac6dc5759 snapraid-3.1-windows-x86.zip
99617ef379c4e46cc4366f2b3baced653f786ef08a40d74dca23a11a9240b096 snapraid-3.2.tar.gz
94d121d8cc0b9ab7ef1648e42edbfe1cfc602231c86a086d21984177da566f77 snapraid-3.2-windows-x64.zip
1d1ed69d3eab8247a7444e603ba09a56ec77979d3865489b2d8a7fc5db65848f snapraid-3.2-windows-x86.zip
c5a6e77613fab5cecb1aa55750f2045934d9374ba70471b6d35296c34509e5a9 snapraid-4.0.tar.gz
a59c911fef0d4d3e95d5521c6a180b40c455870be3ee9dbb5991b05b2cdd2f05 snapraid-4.0-windows-x64.zip
97ec4ae7b6ec6cd05e0c2ae835def526d12c35fa3546d27bd93978d978cd62aa snapraid-4.0-windows-x86.zip
7f5a37be7b8b78056d6602cef8ef702fe4f0d0b6ac3fa4bcefeb70743425b6fe snapraid-4.2.tar.gz
bf7861274639f2e9e5819ec3a89eed911cd79a212824fe3a6b64e45c0d1e2cc4 snapraid-4.2-windows-x64.zip
c7d9330be1936d7d7b07c51668fc8d3f88ce270e9e74945288d75eda2405a377 snapraid-4.2-windows-x86.zip
09f1ebfb5c45680c50651e94287d59e58260c46aee922d8864fb06fd591740e8 snapraid-4.3.tar.gz
ba1008452ff679c1e144206c73a81e4cb2689006c9ce37b60ceab45ef4c99dda snapraid-4.3-windows-x64.zip
23b21e162d5d18a4f68c8635e1f111fddb91d380514d8ddab9040b18a49d9994 snapraid-4.3-windows-x86.zip
aa22ea2e01a8db45ba43a3139d763cb2d12548de96f957a1ea1b5f80f04a4d83 snapraid-4.4.tar.gz
ca68dd88741290a6ee6494a9186b58766cab2b838f4a55ab23921b524b15ee82 snapraid-4.4-windows-x64.zip
3d9cccc2080d1435e7e747c7eeeffc85e0b68ad45b390c236de321b8aca44d46 snapraid-4.4-windows-x86.zip
ba43b0534197c6064b7a171321762be2ac2c848d4849c578007cc65aa963bed5 snapraid-5.1.tar.gz
54a31c5c979b9c3ad481cd918a48e220f11ce04de0a8ec6f41a957af7ba259fc snapraid-5.1-windows-x64.zip
6758966b3a120bf5b97f21748f649b2f147800b10377a0ee69d922be318ee399 snapraid-5.1-windows-x86.zip
eab07c21201eceb4204f8039f021ff0032515719aa5e640c330da45dd8b8e7a3 snapraid-5.2.tar.gz
554cc7be40fff0a0f249522bda957dfba229066e81102624b979213666b1aaae snapraid-5.2-windows-x64.zip
44f909157ba89d769af59e971c71b15bd38dfd62359b2e2c7eeb8cef0f9dc081 snapraid-5.2-windows-x86.zip
81e00fced6bb040d49aa6e3dc6fda97f22bf677d00f6c0c490e312c23222b421 snapraid-5.3.tar.gz
2627b2491b4d432a311cca1c924f4b40cef7a64c930b7e5eca55b3b9a8a62e61 snapraid-5.3-windows-x64.zip
d1019dc29922d4787c3fd9d4222dfc3b84a6a2e0c6b2db298340747238d8fb46 snapraid-5.3-windows-x86.zip
d836200058b98f189e576ad5619d4ffcd867e5dc8d2a4b775bff07d4f201c938 snapraid-6.0.tar.gz
06f2e56bc30c89e4a1561ec32cf72b240765456505f17da539af4b4338a6b12c snapraid-6.0-windows-x64.zip
6ae0a3fa973a28c64489bc28d7a7f4b354d3fc6703bcb83ef661cf76e994b34d snapraid-6.0-windows-x86.zip
1709c09b0e0699ce38452be7340c279c561b91433a6810600386bb9d8c0491e3 snapraid-6.1.tar.gz
40d995a88a23d799a32eba15f64c983a012771c527208cec2ad98787a45ef4c3 snapraid-6.1-windows-x64.zip
f8e09b3300717d1f9ee9b69bb132038642839c19a15a1f47810f3de10ad559eb snapraid-6.1-windows-x86.zip
b182328227ed9b87b01037f7d005d38a6e3cfb0f675e919978c696dcc6246787 snapraid-6.2.tar.gz
72ccfbf6548b83bd6f229d4862763a4e4cf6001c94d9ee84bf7b2a379a9a7743 snapraid-6.2-windows-x64.zip
55f1bc131f9148ed2b52e0e252c7155e50f5b4383fe82cd74ec2edace2ddc9c6 snapraid-6.2-windows-x86.zip
1f1961385b865bff5282bd16aff76f372f3ed19b685ef7a3b27d907a499385d2 snapraid-6.3.tar.gz
bb55d74d6b3cb08b21f70fded8b706ec1e790222cb265524cb2dc5499ec73391 snapraid-6.3-windows-x64.zip
3e4fa161ea26b8472dbbbfb4e61b34aca904ff9621f5afafbc83280d334a89b2 snapraid-6.3-windows-x86.zip
7cad74422d45c8a05435a03d3228a2d621a962fb866caedde0497f180bd9f60d snapraid-6.4.tar.gz
59471b49733c36acfbdeb16b28fbee063c4582abab2c9168abc7abc75610f9fc snapraid-6.4-windows-x64.zip
abe80b7c019980da2af5e07e0ea8b1ac1e1cdb2eb663483c07dab6ad6bd15985 snapraid-6.4-windows-x86.zip
554684520204d45f8b7cee9abb0269dd2bdba272cb0130c3b26062bea551a791 snapraid-7.0.tar.gz
a617b435f97cd746b4076d00cde68f947cca21adaca6ce603fec4676827b7ae9 snapraid-7.0-windows-x64.zip
301af727522912184f6d4a8290757950fed4577da625d9951809ff69f50b6e4f snapraid-7.0-windows-x86.zip
dd9005b6d7ea701e4aa0f854a0e34dabe68d7765b75f12fc6b3e1fda4d5c2cef snapraid-7.1.tar.gz
0d3a9625a6156ffe9b9eb4703aa2fc63141c51b83c69e98fbecce5430b1980e4 snapraid-7.1-windows-x64.zip
e0afdb753ae6a3bb3484a1bfe1cf01b9178010a8c11604e4bbc44b2f83884842 snapraid-7.1-windows-x86.zip
a912628dd003b3d70f2736629d48eeb738e7d27cba74014001dcc46fce3bc3be snapraid-8.0.tar.gz
9c2158fb9e2c08570f6a03f5cea7ab68d2a424adb1f42bb6b3d970ba9dc8a15d snapraid-8.0-windows-x64.zip
3c2c4357450564010d80bbd2cb1d5583281885b32cf659a0cf3dadce4766e167 snapraid-8.0-windows-x86.zip
6bf89a1319ac3403958cd2c98a9c6102728c0070cfa1aedd90c4561d93c54e5d snapraid-8.1.tar.gz
83ad064d5c3938fdacb989983c6b0fafa0932c236dc4baa93512f3c97fa019bc snapraid-8.1-windows-x64.zip
25e5cffade3667348a242f44fb23719328d578010d79bb28a5cab662fc75916b snapraid-8.1-windows-x86.zip
dff5f4e9a41865313ddd60b6379d5c0b308880d33f197934f98313e8241c6274 snapraid-9.0.tar.gz
624c3aa6cb0bdb7c90566545ca831721ea5e543c843418a00ff4de753af07953 snapraid-9.0-windows-x64.zip
6ace6dafacd902bdf058e42c7d39591e327aef1bb19a94b05496f0f14aca8e1e snapraid-9.0-windows-x86.zip
397fdd7709e941e372b37025457794f8b0ce63a5a8455703ad17770cbccd3823 snapraid-9.1.tar.gz
4c56b2c5d556a3685239e444cb58ce84c398e86a173be34ff7cfa3a2b31a5b34 snapraid-9.1-windows-x64.zip
515ca2078cdcb58b59afc005770a06648d8f17adb27afa5751ca6f68de2c05c6 snapraid-9.1-windows-x86.zip
77de90645a5debd177995d7897d58277b7c778632f0d9852740f5670f3321176 snapraid-9.2.tar.gz
483d96dc8937f6df48b7f454f8ec8f7ee51b5e973fa8f004e59048d60525d2fb snapraid-9.2-windows-x64.zip
99c950ff31c73cc55a1b83e4dfdbb6e1717420af54721f8bbe813fbbba484e04 snapraid-9.2-windows-x86.zip
61c4f3ce8bd5ebb1178fe76ab5933e90c4cead6dba31669f11e262d258c2b2ba snapraid-9.3.tar.gz
178e743b6246265f936e63ab47fe2a942bf414992cd752478854b81bdf264913 snapraid-9.3-windows-x64.zip
2cb888833cdddc82431822f818de0cfd046ceda5a7aa17bf9c410b6147ed7e20 snapraid-9.3-windows-x86.zip
f7dcf19480256fc2c1db9ab976aa12f786e76da6044cc397f0451524e8031ad6 snapraid-10.0.tar.gz
a3b4b2563f44f17072bb20963d61aae53d9f0e6b9446509fee76bbfa9b51fd23 snapraid-10.0-windows-x64.zip
95a1859163beb8c8d02208b27ecf5298068972498c7e2b99b488693ad5f8f133 snapraid-10.0-windows-x86.zip
30a72b8853ea750128c96784b73bb55f7faa4b16367b2e03f40c1f78515c5771 snapraid-11.0.tar.gz
af6f24adb81008e7ccdb7a8f2c46d1187542bd290294563de90acf5d817d772d snapraid-11.0-windows-x64.zip
fedc7591c8de0ce2775482e6b18033cdaca62078a0a16d45421d5fb5dd5615d6 snapraid-11.0-windows-x86.zip
b9acafeb6cece61fd426f08362b596ba89eea0564231955b82156fd09c0e6884 snapraid-11.1.tar.gz
6468d1a55a9a8043eae3c7c292c908c0fbd1974af3f175df23d39dd4748d9bf9 snapraid-11.1-windows-x64.zip
e70929b44ed88701b542abbccadc57dd89469f58cf7d6ca0bf80ce706d854553 snapraid-11.1-windows-x86.zip
735cdeb7656ac48cbb0b4a89a203dd566505071e465d5effbcc56bcb8fd3a0d7 snapraid-11.2.tar.gz
025faabb6390b6af600034523e5988e14160015b835541d8427475ca7fa52057 snapraid-11.2-windows-x64.zip
de16e2083054f34e1206b552bd05c64218c0dffcf787d716c6639f8728457d20 snapraid-11.2-windows-x86.zip
d35ad92157936db3411e2cf7325665fc59e2d159204f9424895cfa9f33122af1 snapraid-11.3.tar.gz
b764a3341783d4694242412e0fca7c112e44e84a4a89a7c27b0f74a836a84baf snapraid-11.3-windows-x64.zip
f8e51bee80ae0223f402afe68f5192f1036434bab816c42333bf2e5f9fbc82a2 snapraid-11.3-windows-x86.zip
1de47b8277c7dd9c339396efdd2b12a865ff82fdf6ab47cb945f2e21717451c9 snapraid-11.4.tar.gz
0734ca7a521ba7c05eea6898f481ca812d2a2d78da4545f7990cd27e6381dc75 snapraid-11.4-windows-x64.zip
061075df60b584ade5c76551ca54d76726441421576a544cdfd621acb23d55e1 snapraid-11.4-windows-x86.zip
1f5267261bdbcf4d48b9359ce67184df11905590739140f740327fb73bcecafa snapraid-11.5.tar.gz
e18f6b825a25b71947c2c41a315440a3d394de348afca80e2ab13a525bbb8a2b snapraid-11.5-windows-x64.zip
a66753201e55c115699df78f89dd562c1b71e876aba5be35fcaf507bfe1e9e52 snapraid-11.5-windows-x86.zip
f030a3830449a78d10af41320da0be21c60f88dc8d328ebd056e0eb7596161cf snapraid-11.6.tar.gz
8a3b8fd240285b5abf62c3ce222a5c674b475a83b3c48a40e457d34bfbcd1744 snapraid-11.6-windows-x64.zip
e8e9140423552cbccbe9a162100a830cd7d2e29bae0893cca9f5bd1943393508 snapraid-11.6-windows-x86.zip
f07652261e9821a5adfbfa8dad3350aae3e7c285f42a6bd7d96a854e5bc56dda snapraid-12.0.tar.gz
a9cd1e30042b09ecc42b508955a1c1144b446a0399c83ecfb78b5455d528938c snapraid-12.0-windows-x64.zip
a037d16bb9d226da2c88df00e410f9e637f1acb6153ac078c9a3805e721282a6 snapraid-12.0-windows-x86.zip
49337d9bafa96c2beac0125463bd22622be2fc00f3b4dee7e4b0e864d2a49661 snapraid-12.1.tar.gz
23196a373b4c7a327a207f019ea833f888977f6e48743b0060706f67fbb1c13e snapraid-12.1-windows-x64.zip
488e3b57323fd55c1bccc14a051d4048a1a7b7b5d6440ece30b5161bda9f5498 snapraid-12.1-windows-x86.zip
9d30993aef7fd390369dcaf422ac35f3990e8c91f0fb26151f5b84ccb73d3e01 snapraid-12.2.tar.gz
1f08ee889b4e0d221267ad011cfbd6f3ebdf94a8809ba2b2d79dbb0751a7c06a snapraid-12.2-windows-x64.zip
daaccc71a2b2cf3d16d021d0c1f7db20e49fbaebea5cda6c301bf41bce8df073 snapraid-12.2-windows-x86.zip
1f27aba6e5db3929474da9c472fc4a3bc51d4a83aa5385af6b09afc9f68d6d44 snapraid-12.3.tar.gz
ffdd430f5f1ad8fba5bd0707bd860b0d3dca55cb8aeca633804638d64b5f0550 snapraid-12.3-windows-x64.zip
579d24cc607d0668e6f17c905eb75e409086a58f466c6fae2943c8e2fc8de039 snapraid-12.3-windows-x86.zip
bc15ad9c42ddf9bd70033562a10e9b9fec43afed54c48fe22da4b6835657ec1b snapraid-12.4.tar.gz
5a5c398b2941fe0d0ede3dfbedaa2fd689dacc6c6d7f537dcd3f276d1c02af8d snapraid-12.4-windows-x64.zip
7f4153af7c9d270ce1e2dac8dc6921d8f284f99f6db1eb3a0ddc80ae1da4f0c3 snapraid-12.4-windows-x86.zip
0282a9eec3301cd608dc45d9182b6d207f9fd4d25828c9deb329a015c77cb4e2 snapraid-13.0.tar.gz
e2f44b06d2065226e6d2b184f9bf046bb0ce5144a585eadb14f83e19c349cc86 snapraid-13.0-windows-x64.zip
1b83a31e5e0ad25701ad58779b125d194426e3f3715f1a51cf81c993c2921e4b snapraid-13.0-windows-x86.zip
59e10835c0397193cb27969852a51059f0b0b9abb6cec2353f3052f6bd18e85d snapraid-14.0.tar.gz
8a917bb29b19fb32ce59cd18d09059ac53b84df6a33da798e6f28f552099f4b4 snapraid-14.0-1-x86_64.pkg.tar.zst
264f66d3092a47c64439fb3d2bded6ce4ec0b3cbc5b5c1f4f3c1ac8bf05a4767 snapraid-14.0-1.x86_64.rpm
59b8b09e20a5937e0cd2798b1256eefa1cd27bd3f1c24b5e4dee32e6b25c1553 snapraid-14.0-windows-x64.zip
b6a144161e7240c754947d5ea4f637f59006cbdaed68c2f285f440c257e7590e snapraid-14.0-windows-x86.zip
b67183342cc4160891dfdf10452f1c79e71bb7887c54fcfb81cd2ded68b3bd37 snapraid-14.0-x86_64-1_am.txz
b33e19558ad0f29f1c8d3907a772377f1125f19b44003db8b8df05cec46cd7c6 snapraid-14.1.tar.gz
d0cb38415284e88cb6f7253ef8389aa207c3689e0276196808773bd37aeb6552 snapraid-14.1-1-x86_64.pkg.tar.zst
a754c6acd9c0efd8de89b698ff7bf422299f30de222c99db42a597b21f272429 snapraid-14.1-1.x86_64.rpm
0bb740d84b446aafc87fb8f188cb87d1429a7c3243b9339633f8a237dfc2b987 snapraid-14.1-windows-x64.zip
f796fc232bc578e9b3007e50dc543dcb9a8a9ab721eaf0b805a0e25c53e573e5 snapraid-14.1-windows-x86.zip
a15c366093e7184b72e51797fcf6429858374810c35694a0c7fb9cb044c5f7ff snapraid-14.1-x86_64-1_am.txz
57da8c813b12dd91bfa5b145b7529f84e227a301394da109fa64f39479c14a1b snapraid-14.2.tar.gz
79c91f03ee8153bd4e1be734ef45778eaf2aa77d2166d6bc7e69ddff8e3c6937 snapraid-14.2-1-x86_64.pkg.tar.zst
7ec5671902a84f806e263372edb98baa4be8a181158515a998deb4b842c974dd snapraid-14.2-1.x86_64.rpm
ea9f459c132cdeeda22f0a51d06cf2d926acfc816d742c4f8d05f0c8de6c3539 snapraid-14.2-windows-x64.zip
a1ae6ed8851e60092fc61a6b2bcceef0404d3f0e1d41bc6ed129980ff24da1b9 snapraid-14.2-windows-x86.zip
f11c3279a2d32d39743826da2cd6abdaa213fa402ecfbfe093dfeed2e1ba032c snapraid-14.2-x86_64-1_am.txz
29cb416eda9beac436c2994543938c01f28555a11a24dedfe102677c9669080a snapraid-14.3.tar.gz
b9d1745ebd6afde38a3f33ae1f2066f1e2adf57877565e15c2f92a21dd6102db snapraid-14.3-1-x86_64.pkg.tar.zst
2580344b374a5f8a12504ded8063d5f94984bd8249a1b62c2f5fb6068a2d8334 snapraid-14.3-1.x86_64.rpm
223dc51189ab4b9d11a2cd47c39190b4fb22f3b515b75975fe6123fddb6d6fea snapraid-14.3-windows-x64.zip
48df1f810271d93a4bc2665fb145ec1225320990db4d9558c67152ab8bcd4b4d snapraid-14.3-windows-x86.zip
04da63b992fbaa961ed0060245947b9090abcedb569ec79c1bf012ca0050e1a1 snapraid-14.3-x86_64-1_am.txz
941467eb69a055028a68484c83aef6b193808914729ab3d3efe0cfd47c2352ab snapraid-14.4.tar.gz
743edf67d2bb6657220da1262cf0ebd1ff871ae87c816bcaf2568de80eeef66c snapraid-14.4-1-x86_64.pkg.tar.zst
bf01ff0956adf0b489f8d85a18146e2450827c96f58087ce699113888c46194e snapraid-14.4-1.x86_64.rpm
5ed9868d263f98978fde7d6a559afd38d0c4ddc85fd753c46e8e11799518c92b snapraid-14.4-windows-x64.zip
64b7499bee20515bf57f2ffcef14a0b1e9c2ba19f0bf897fe8e8fd2f4d2bacbe snapraid-14.4-windows-x86.zip
6de85b1703df0cd30bbbab9ef2cf27d444e97a3c202442ef677f0f484187672c snapraid-14.4-x86_64-1_am.txz
ccbbf089134a2963147aeaa535911ad1868a2786daf54786d633837d4130da54 snapraid-14.5.tar.gz
8621b7115a30d488c86665d20d6c4c8c99f0018103dba6bcac52b0dee4832c30 snapraid-14.5-1-x86_64.pkg.tar.zst
239b9f546e84f9c2db160688164af9339f1a1252e8573eab16cb9fd225ee19af snapraid-14.5-1.x86_64.rpm
52aed58e0802d65f2e5c543f620958ea03f3c2ec5098874085685b581ef94dad snapraid-14.5-windows-x64.zip
573c0460388e9ceae8b30726cf88c97d3012e223e9781dd71e67231e3b6b54dc snapraid-14.5-windows-x86.zip
bfdf468f9a5df195e1cfb51ef423d61866470efb16c0e734f82c009865258bc4 snapraid-14.5-x86_64-1_am.txz
056f86b4f69265692d15d742ea7427804ef2e873aec4263425abb138be86fb08 snapraid-14.6.tar.gz
0c5ed569aab38586539cfc8fa148190b025e89418c8accdc22004716246c3d9b snapraid-14.6-1-x86_64.pkg.tar.zst
ebbae62aabadb02813441662256197fb37bf785b0e7b31a9c10261b523b031f0 snapraid-14.6-1.x86_64.rpm
bbac43675a18a0b465cbc519cf047b395c873caa736f48749b26dc40777d20e5 snapraid-14.6-windows-x64.zip
e58f1b5859c52c289e06508f297c9a98d8cddb4ca67b8ac210ad4d2696b468f5 snapraid-14.6-windows-x86.zip
dce1bfd86784484c709a9e0fce0a8a22a8201793f8b5ca8734e766022ad05b54 snapraid-14.6-x86_64-1_am.txz
fe4c71d444bade85fe390d2a58de1ea34b53109278b96fb19bc9ac9133eb07ff snapraid-14.7.tar.gz
eaac4391c89650c7fe9fd263a31533bbf6d06b0c28eb4ee21590e9472aaa5f79 snapraid-14.7-1-x86_64.pkg.tar.zst
4be9f5f41ba744870b9315e7d3e7e162d74f280a20f669b63dfbdc7bb819f91e snapraid-14.7-1.x86_64.rpm
dce8b1345b04cf99ec8fc41fd0c5ed9ea38e64050077a7fb12a03b21e35deef9 snapraid-14.7-windows-x64.zip
3ff33a921ac22672eb8267eb5c52721fbd3de35fb2bb373a6056ba4281a800b4 snapraid-14.7-windows-x86.zip
e0d8178b2d6b4ab8302001eddd10f09bbbdf744020bff2f0576b405a0c96e294 snapraid-14.7-x86_64-1_am.txz
bdf649024f6bcbf40261bc848dd6f9739152b0bbb1b074b3d88ef3dee00fe241 snapraid-14.8.tar.gz
51fc7419aa281229e9d5181eadd3bb0160f5bc925de44819e0bc5187ba9164d0 snapraid-14.8-1-x86_64.pkg.tar.zst
da67aabf0b334dbb4f564fa111e2825351b3263b4d6585fa68342d0cc0868457 snapraid-14.8-1.x86_64.rpm
ec96896837f5ffd4ae1f7de01b4472e92bc7b3451d2c882b1d73a5b5fa5fcda8 snapraid-14.8-windows-x64.zip
b12594951cb8060e8e0d9d26c00c8ebaa37dcd0c08edb7cc530c6b483d7b9d73 snapraid-14.8-windows-x86.zip
bf59b701c1db4ffe0e8ed991b5849d2e83b3ab3d390b433246d38f70f5a37520 snapraid-14.8-x86_64-1_am.txz
40c216979d9d9853248060497341f74feaa07c8ae15927b6b14972c4f9d143d5 snapraid-14.9.tar.gz
e11c452e2adec376e6fcaee9ff2ec4de4e943c35690229c9c67056c5eaed52a1 snapraid-14.9-1-x86_64.pkg.tar.zst
3f6d5f6238190ab40f12e5c5573c6796d61db90183259dc45bee1b57eda32ce9 snapraid-14.9-1.x86_64.rpm
84af790cd25c8f2d773386bca7320cb5cf81706f850eb1fda33d4b9ff4e0d692 snapraid-14.9-windows-x64.zip
7ec39de0cf7cabd09061bfc54848084b4505e77b27556850fc53cb5f23080003 snapraid-14.9-windows-x86.zip
40cee688cb1a322810eaac4e3655313c0075b791e18783bec2588084a9e47f09 snapraid-14.9-x86_64-1_am.txz
27be09151c8e779019da7d9e0501b03f56ae83da489cdaf5cd85463075cec9a2 snapraid-14.10.tar.gz
6f5a31ee04649c9b2b7b0612619f401f160c4f1a4a56947ff50381cc6036b8cc snapraid-14.10-1-x86_64.pkg.tar.zst
461778095cd40e9ef1231999dd4924499c1f6cab23e233ab811f37e29b81aefe snapraid-14.10-1.x86_64.rpm
6e8892175bfe240ae7828d513342180a249511a2d5baf8c003ae8b2bb82e0f46 snapraid-14.10-windows-x64.zip
1ec0572359fb31f2827702d792db0bdf6a95161eb9e2a6deff2bdc7e1f5b794b snapraid-14.10-windows-x86.zip
6930d629c73b5307ec32277310ed13887b1bd051e30dc41c75b4752040032d1c snapraid-14.10-x86_64-1_am.txz
ceba44e15566386d923d6895ecab81f7437848b03a4cf9585c02d3636197ce19 snapraid-15.0.tar.gz
9d55d0308ce41beb29956b59f9d2e32d419c930118266d3e08b15f658119f4fb snapraid-15.0-1-x86_64.pkg.tar.zst
ad66c0b4c016775c9a759adf2a5202bebb357d319b0063b9cf68befde9a67363 snapraid-15.0-1.x86_64.rpm
704706c21b432719c4da8cd237c1f26327af89c86604dc339a38d63574004a22 snapraid-15.0-windows-x64.zip
58b3ed90307e41b7a6e862d2dc070204c98b5c3ac24718e2fb9fe03e275bc2ce snapraid-15.0-windows-x86.zip
9483df5a39a8b59c32433331ac92a4eef54dcff4722694a5bc5e89bcefb6b3b0 snapraid-15.0-x86_64-1_am.txz
fb2d6a9cf9c8ea30c6962f4a48764dc9012fe61d6e23f40a8d959dadea02278b snapraid-15.1.tar.gz
5e627e08caa8d7647fd40e5288b8d59846d1f3d65d586bae74a57cd99a23f497 snapraid-15.1-1-x86_64.pkg.tar.zst
8922234dd566c876b17cbaadad6a22690d05240250455e504513906d933e16dd snapraid-15.1-1.x86_64.rpm
64849f463986d0d80b948dbb07e9af6402bed230a9cf17dbd1110199aca56486 snapraid-15.1-windows-x64.zip
f7be230f7849d89941a280dc8c2cc6e158844e0fe6f00adbb6aa9ac0f65322b8 snapraid-15.1-windows-x86.zip
4dbd01ab2582a74fab4d7ee8f9b11966d4188fba9eedcd31fcc0a5588cd0c702 snapraid-15.1-x86_64-1_am.txz
128b5b0f80a6a0911e77ed3b5d9d81529f5ea1d8fffbb5112e3af3467d80464a snapraid_14.0-1_amd64.deb
b9c41ae2e8edbc413abd3172b7ed2da2cba7fa0e631d0f47fc1dafccf7c6e92c snapraid_14.1-1_amd64.deb
e6456b926bb053d34645e31e5e3d8363e952c9869e873eb348abb1149598d331 snapraid_14.2-1_amd64.deb
bfbec7200f96d6ce23bfd6ae43fb2764fe26c9480c5c478b3bb6bb90dd707a07 snapraid_14.3-1_amd64.deb
50863cc6067f23449ba67e0cae456d74a1eadf2a19612a70067bb4e7cc88131c snapraid_14.4-1_amd64.deb
3ff971ba7da0336e3f86fef7218437e680649abcbd6a60607aee946f7ac99695 snapraid_14.5-1_amd64.deb
b71b556da4be6263a904fb8ac489933875467adbb920dd3911e54d87e9637ca3 snapraid_14.6-1_amd64.deb
35b156fc4d5c34339eed7e7d73e22a76e646879ecf6846b5ca20f7992ff55640 snapraid_14.7-1_amd64.deb
c0e00a25b9bce40ff74f5a55401c3bfedac1881fd99aaa90a692f5858d417f7d snapraid_14.8-1_amd64.deb
09064689a64d965ac33ee89fb8b2cc14dfec0745f2b3b86a78f377fc353b7e07 snapraid_14.9-1_amd64.deb
15f5fd9f639912c94daae9d75d3567b7a3fc0e18475880f972acd8d8e9e0992c snapraid_14.10-1_amd64.deb
845091e7eeb2495fc3899dc6e8fab2c3fe7a5945f345c767a7603dab90e2cb84 snapraid_15.0-1_amd64.deb
974cd45fc8f44d5642b49bd9b30e81aca2bcd7689877f9fa73d1e58d3f1b5bda snapraid_15.1-1_amd64.deb

677
COPYING
View file

@ -1,11 +1,674 @@
The SnapRAID project as a whole, including all its contributions and GNU GENERAL PUBLIC LICENSE
modifications to included libraries, is provided under the GPL-3.0-or-later Version 3, 29 June 2007
License.
The RAID library is provided under the GPL-2.0-or-later License. Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
The TommyDS library is provided under the BSD-2-Clause License. Preamble
The full text for these licenses is available in the LICENSES/ directory. The GNU General Public License is a free, copyleft license for
software and other kinds of works.
All contributions to the SnapRAID project are subject to this COPYING file. The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

View file

@ -1,22 +0,0 @@
# If Makefile exists (generated by ./configure in this directory), delegate
# directly to it so that in-tree builds work normally as if this file were absent.
# Otherwise, redirect all targets to linux/Makefile for out-of-tree builds.
# Named GNUmakefile so it takes precedence in GNU Make without conflicting with
# Makefile on case-insensitive filesystems (Windows/macOS).
ifeq ($(wildcard Makefile),Makefile)
include Makefile
else ifeq ($(wildcard linux/Makefile),linux/Makefile)
all:
$(MAKE) -C linux $@
doc:
$(MAKE) -C linux $@
cp -a linux/doc/*.1 linux/doc/*.txt doc/
.DEFAULT:
$(MAKE) -C linux $@
.PHONY: all doc
else
$(error SnapRAID is not configured. Run './configure')
endif

980
HISTORY

File diff suppressed because it is too large Load diff

28
INSTALL
View file

@ -1,33 +1,25 @@
SnapRAID INSTALL SnapRAID INSTALL
================ ================
To build and install SnapRAID, download the source code from http://www.snapraid.it As root or user type:
and unpack it with the following commands:
tar xf snapraid-.tar.gz ./configure
cd snapraid-*
To configure the build environment and compile the binary, run:
./configure --prefix=/usr --sysconfdir=/etc
make make
To run the application's correctness tests, execute: When you have to check for correctness the application typing:
make check make check
If the tests complete with "Success", install the application and documentation If it terminates with "Success", you can install the application and
using: the documentation running as root:
sudo make install sudo make install
Note: The SnapRAID application does not require root privileges to run, but To start using SnapRAID you have to change the example configuration
you may need appropriate permissions to access the disks. file snapraid.conf.example to fit your needs and copy it in /etc/snapraid.conf
To start using SnapRAID, modify the example configuration file To get more help, see the "Getting Started" section in the snapraid manpage
snapraid.conf.example to suit your needs and copy it to /etc/snapraid.conf. typing:
For additional guidance, refer to the "Getting Started" section in the SnapRAID
manpage by typing:
man snapraid man snapraid

View file

@ -1,8 +1,9 @@
SnapRAID INSTALL for Windows SnapRAID INSTALL for Windows
============================ ============================
To start using SnapRAID, you need to modify the example configuration file To start using SnapRAID you have to change the example configuration
snapraid.conf.example to suit your requirements. After editing, save it as file snapraid.conf.example to fit your needs and copy it with the
snapraid.conf in the same directory where you run snapraid.exe. name snapraid.conf in the directory where you run snapraid.exe.
To get more help, see the "Getting Started" section in snapraid.txt.
For additional guidance, refer to the "Getting Started" section in snapraid.txt.

View file

@ -1,22 +0,0 @@
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.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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.

View file

@ -1,340 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

View file

@ -1,674 +0,0 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU General Public License is a free, copyleft license for
software and other kinds of works.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
the GNU General Public License is intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users. We, the Free Software Foundation, use the
GNU General Public License for most of our software; it applies also to
any other work released this way by its authors. You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
To protect your rights, we need to prevent others from denying you
these rights or asking you to surrender the rights. Therefore, you have
certain responsibilities if you distribute copies of the software, or if
you modify it: responsibilities to respect the freedom of others.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must pass on to the recipients the same
freedoms that you received. You must make sure that they, too, receive
or can get the source code. And you must show them these terms so they
know their rights.
Developers that use the GNU GPL protect your rights with two steps:
(1) assert copyright on the software, and (2) offer you this License
giving you legal permission to copy, distribute and/or modify it.
For the developers' and authors' protection, the GPL clearly explains
that there is no warranty for this free software. For both users' and
authors' sake, the GPL requires that modified versions be marked as
changed, so that their problems will not be attributed erroneously to
authors of previous versions.
Some devices are designed to deny users access to install or run
modified versions of the software inside them, although the manufacturer
can do so. This is fundamentally incompatible with the aim of
protecting users' freedom to change the software. The systematic
pattern of such abuse occurs in the area of products for individuals to
use, which is precisely where it is most unacceptable. Therefore, we
have designed this version of the GPL to prohibit the practice for those
products. If such problems arise substantially in other domains, we
stand ready to extend this provision to those domains in future versions
of the GPL, as needed to protect the freedom of users.
Finally, every program is threatened constantly by software patents.
States should not allow patents to restrict development and use of
software on general-purpose computers, but in those that do, we wish to
avoid the special danger that patents applied to a free program could
make it effectively proprietary. To prevent this, the GPL assures that
patents cannot be used to render the program non-free.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Use with the GNU Affero General Public License.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU Affero General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the special requirements of the GNU Affero General Public License,
section 13, concerning interaction through a network will apply to the
combination as such.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, your program's commands
might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.

File diff suppressed because it is too large Load diff

43
README
View file

@ -1,29 +1,30 @@
SnapRAID SnapRAID
======== ========
SnapRAID is a backup program designed for disk arrays, storing SnapRAID is a backup program for a disk array.
parity information for data recovery in the event of up to six
disk failures.
Primarily intended for home media centers with large, SnapRAID stores redundancy information in the disk array,
infrequently changing files, SnapRAID offers several features: and it allows recovering from up to two disk failures.
* You can utilize disks already filled with files without the SnapRAID is mainly targeted for a home media center, where you have
need to reformat them, accessing them as usual. a lot of big files that rarely change.
* All your data is hashed to ensure data integrity and prevent
silent corruption. Beside the ability to recover from disk failures, the other
* When the number of failed disks exceeds the parity count, features of SnapRAID are:
data loss is confined to the affected disks; data on
other disks remains accessible. * You can start using SnapRAID with already filled disks.
* If you accidentally delete files on a disk, recovery is * The disks can have different sizes.
possible.
* Disks can have different sizes.
* You can add disks at any time. * You can add disks at any time.
* SnapRAID doesn't lock in your data; you can stop using it * If you accidentally delete some files in a disk, you can
anytime without reformatting or moving data. recover them.
* To access a file, only a single disk needs to spin, saving * If more than two disks fail, you lose the data only on the
power and reducing noise. failed disks. All the data in the other disks is safe.
* It doesn't lock-in your data. You can stop using SnapRAID at any
time without the need to reformat or move data.
* All your data is hashed to ensure data integrity and to avoid
silent corruption.
For more information, please visit the official SnapRAID site: The official site of SnapRAID is:
http://snapraid.sourceforge.net
https://www.snapraid.it/

27
TEST Normal file
View file

@ -0,0 +1,27 @@
SnapRAID TEST
=============
The regression test of SnapRAID is run using the command:
make check
You can also run the regression test in valgrind with:
./configure --enable-valgrind
make check
To run a coverage test you should use:
./configure --enable-coverage
make lcov_reset
make check
make lcov_capture
make lcov_html
and open the file ./cov/index.html in your browser to see the results.
To test with the clang static anlayzer use:
scan-build ./configure
scan-build make

387
TODO
View file

@ -3,189 +3,65 @@ SnapRAID TODO
This is the list of TODO items for SnapRAID. This is the list of TODO items for SnapRAID.
16.x Releases - Next
=============
* Support a `[power_control: off]` tag in `smartctl` options to disable power * In sync if a data error is found, we can mark the block as bad, like in scrub
management (`up` and `down`) on specific disks (e.g. for SAS drives that and allow sync to continue.
fail to wake up on write). Emit an attribute tag in probe for snapraid-daemon.
* Enable MuseAir and disable random seed * Detect files moved from one disk to another. We won't be able to reuse
parity, but we can reuse the hash to check that the file was moved
correctly.
* Add a new 'restore' command, similar to 'fix', that recovers a whole disk * Add a way to list the content of the array. A new "list" command ?
using the same multithreaded approach as sync/scrub. Something similar at "diff" and "dup".
* Use statx() instead of lstat() when scanning directories.
* Integration with MergerFS ?
* Restore ownership and permissions, at least in Unix.
* Restore directory timestamps.
* Check Reliability Test. We can derive Failure probability from MBTF
https://github.com/linuxhw/SMART
https://github.com/linuxhw/EnterpriseDrive
* Check Scrutiny Thresholds
https://github.com/Starosdev/scrutiny/tree/master/webapp/backend/pkg/thresholds
* Check updates to smartctl drivedb.h
https://github.com/smartmontools/smartmontools/commits/master/smartmontools/drivedb.h
* A "dependents" output option to [--test-fmt file|disk|path|dependents] for LIST.
Example, snapraid LIST --test-fmt dependents >FileList_with_dependents.txt
The goal is a filelist that, for every file, includes full paths to the dependent files
on other data disks needed to repair that file (in addition to the parity data).
See: https://sourceforge.net/p/snapraid/discussion/1677233/thread/6e872fdae0/
Future
======
- Major
* Optimize `sync` on Btrfs by using `btrfs send -p <prev> <curr> --no-data`
to identify modified files and extent offsets, avoiding a full filesystem
metadata scan. Parity recomputation still reads from the latest snapshot.
Store the Btrfs snapshot generation (and UUID) in the content file to verify
that the parent snapshot strictly matches the content state before diffing,
falling back to a full scan if mismatched.
* Size-Based Checkpointing (autosave) using a write-ahead log (WAL).
Instead of writing the full content file periodically (autosave), write incremental
updates to companion `.wal` files. Use the existing bit-efficient `STREAM`
abstraction (`cmdline/stream.h`) for the WAL. For each synced block entry,
the stream writes: target disk index (`disk_idx`), block state (`state`),
block position (`block_idx`), and the newly computed block hash (`hash`).
This automatically provides:
- Variable-length binary integer packing (`sputb32`/`sputb64`), reducing the average
record size to ~20 bytes.
- Built-in stream buffering for batched writes to prevent mechanical disk seeks,
with periodic `ssync()` flushes (calling fdatasync internally).
- Out-of-the-box support for atomic mirrored writes to multiple content directories
via `sopen_multi_write()`.
- Built-in block-level CRC integrity protection.
Perform a full checkpoint (writing the content file and truncating the WAL)
only when the WAL file size exceeds a threshold (e.g., 50 MB).
- Minor - Minor
* Emergency Memory Reserve for Graceful OOM Shutdown. * Enable storing of creation time NTFS, crtime/birth time EXT4.
Pre-allocate a small emergency memory reserve buffer (e.g., 10 MB) at program But see: http://unix.stackexchange.com/questions/50177/birth-is-empty-on-ext4
startup. Modify `malloc_nofail` (and related memory allocators in `memory.c`) coreutils stat has an example, but it doesn't work in Linux (see lib/stat-time.h)
so that if an allocation fails (returns NULL), the emergency buffer is freed
to give the system breathing room. Then, trigger a graceful shutdown by
stopping active I/O threads and calling `state_write()` to save the content
file (preserving progress up to the last synced block) before calling `os_abort()`.
* Time-Based Content File Loading. * A new 'init' command to differentiate the first 'sync' operation.
On startup, read the modification time (mtime) of all configured content files, This 'init' will work also without a content file, and parity files.
and sort the loading list to try loading the newest one first. Instead 'sync' will require all of them.
This resolves the inconsistency window during sequential renames on crashes. This will also help when running with the parity filesystem unmounted.
If the newest file is corrupt, the existing load loop naturally falls back to the
next newest.
* Add a new scrub option for checking recent blocks. Like -n, --newer-than. * Adds a log configuration option to save log files with the date in the name.
Working the opposite of -o-, --older-than This could help to keep track of what happens during automated operations.
* Add a new -u, --filter-updated command that filters files * In fix an existing symlink with the same name of a file to be recovered may stop
with a different timestamp, to be able to restore only them to the previous state.
See: https://sourceforge.net/p/snapraid/discussion/1677233/thread/e26e787d/
* Allow to filter in diff/list by disk name.
Not checked disks should be allowed to be missing.
* Add an option to ignore subsecond timestamp.
Like when you copy data to a filesystem with less timestamp precision.
* Support more parity levels
It can be done with a generic computation function, using
intrinsics for SSSE3 and AVX instructions.
It would be interesting to compare performance with the hand-written
assembler functions. Eventually we can convert them to use intrinsics also.
https://sourceforge.net/p/snapraid/discussion/1677233/thread/9dbd7581/
* Add a "noaccessdenied" config option to exclude not readable files/dirs.
Like the "nohidden".
See: https://sourceforge.net/p/snapraid/discussion/1677233/thread/1409c26a/
* Don't insert new files if they are now opened by other applications.
Not yet sure how to check if a file is open in a fast way.
In case we can exclude files created too recently, like with a --min-age option.
See: https://sourceforge.net/p/snapraid/discussion/1677233/thread/a1683dd9/?limit=25#1e16
* Add markdown support for output
See: https://sourceforge.net/p/snapraid/discussion/1677233/thread/661cce8b/
* Change all the paths printed in the terminal as relative and not absolute.
https://sourceforge.net/p/snapraid/discussion/1677233/thread/648955ec/ (Leifi in diff)
https://sourceforge.net/p/snapraid/discussion/1677233/thread/5b6ef1b9/ (Miles in check + filter)
Partially done. Now you can control it with --test-fmt
* When a disk is replaced, and SnapRAID detects this by a UUID change, we could clear the
scrub information for that disk.
https://sourceforge.net/p/snapraid/discussion/1677233/thread/ee87901b/
* In fix, automatically --import excluded directory in the config file.
https://sourceforge.net/p/snapraid/discussion/1677233/thread/c80c42e5/?limit=25
* Allow to have "partial" parity disks, smaller than required ?
https://sourceforge.net/p/snapraid/discussion/1677233/thread/e924c663/
* How to handle corrupt copied/moved files ? Now pre-hash checks them,
but if a corruption is found, it stops the sync process.
This is not optimal, because the 'sync' command is stopped instead of continuing.
A possible solution could be:
If a copied block is corrupt, we can recover the original one from parity (if moved),
or read it directly from disk (if copied), and we can use this one to build the parity,
working around the corruption, that can be later fixed with "fix".
This requires to allocate blocks of moved files in parity positions *after* the
currently used one.
* Some programs are misusing the FILE_ATTRIBUTE_TEMPORARY.
In fact, it makes sense as it's a good way to control the cache on the file,
so, despite the name, that usage could be common for not temporary files.
https://sourceforge.net/p/snapraid/discussion/1677233/thread/57d40108/
* Add an option for dup to list only duplicates with different names.
This supposing that if a file has the same name, it's intentionally duplicated.
* In fix, an existing symlink with the same name of a file to be recovered may stop
the process making the create() operation to fail. the process making the create() operation to fail.
The same for directories, when recreating the directory tree. The same for directories, when recreating the directory tree.
* If a directory exists with the same name of a parity/content file be more explicative * If a directory exists with the same name of a parity/content file be more explicative
on the error message. See: https://sourceforge.net/projects/snapraid/forums/forum/1677233/topic/4861034 on the error message. See: https://sourceforge.net/projects/snapraid/forums/forum/1677233/topic/4861034
* Support interrupted operations with EINTR. For remote filesystems it could be relevant.
* Allow to specify more than one disk directories to cover the case of multi partitions.
Different partitions have duplicate inode. The only way to support this is to
add also a kind of device_id, increasing the memory required.
But it should be only few bits for each file. So, it should be manageable.
* Rename sync->backup and fix->restore. It seems to me a naming expressing
better the meaning of the commands. But not yet sure.
* We don't try to do partial block recovering. A block is correct or not. * We don't try to do partial block recovering. A block is correct or not.
But if only some bytes, or a sector, is wrong, it should be possible to recover all the But if only some bytes, or a sector, is wrong, it should be possible to recover all the
rest of the block. rest of the block.
The problem is that we don't have any hash to ensure that the block is partially recovered, The problem is that we don't have any hash to ensure that the block is partially recovered,
or completely garbage. But it makes sense to anyway write the "most likely" correct one. or completely garbage. But it makes sense to anyway write the "most likely" correct one.
- Naming * In the repair() function the euristic to detect if we recovered after the sync, can be extended
to all the previous blocks, because we always proceeed in block order during a sync.
So, if for a block we can detect that we recovered using updated parity data,
also for all the previous blocks this is true.
Anyway, the case where this information could be useful should be present
only if changes are committed after an aborted sync.
* A new 'init' command to differentiate the first 'sync' operation. - Pooling
This 'init' will work also without a content file, and parity files.
Instead 'sync' will require all of them.
This will also help when running with the parity filesystem unmounted.
* Rename sync->backup and fix->restore/recover. It seems to me a naming expressing * Allow to specify the shared path to use to access remote symlink.
better the meaning of the commands. But not yet sure.
Rejected TODO
=============
This is a list of rejected TODO items.
* Parallel hashes using vector instructions. See the 'parallel_hashes' branch.
- Only Spooky2 can be effectively parallelized because vector instructions
cannot efficiently perform 64x64->128 bit multiplications.
best murmur3 spooky2 spk2sse spk2avx metro museair musesse museavx
hash spooky2 6163 17570 24227 *34519* 20612 *27894* 10648 19827
- This small speed increase occurs only in the best-case scenario when AVX is present
and the number of disks is divisible by 4.
* Add a new "commit" command to move changes from the pool to the array. * Add a new "commit" command to move changes from the pool to the array.
It should: It should:
@ -199,154 +75,37 @@ but kept in the same disk of the array.
- Detect deletes, and move file in the array to a "/trash/" directory - Detect deletes, and move file in the array to a "/trash/" directory
of the same disk. For safety no real deletion is done. of the same disk. For safety no real deletion is done.
File with the same name will get an extra extension like ".1", ".2". File with the same name will get an extra extension like ".1", ".2".
- MergerFS is anyway better
* Allocate parity minimizing concurrent use of it * In the content file save the timestap of the parity files.
Each parity allocation should check for a parity
range with less utilization by other disks.
We need to take care to disable this mechanism when the parity space
is near to fillup the parity partition.
See: https://sourceforge.net/p/snapraid/discussion/1677233/thread/1797bf7d/
+ This increases the possibility of recovering with multiple failures with not
enough parity, as the benefit of existing parity is maximized.
- Possible increase of fragmentation of parity allocation
- No real benefit when the array is filled
- Slowing down operation that have to check the whole array.
10 disk at 10% utilization, will use the full parity, requiring to
read and write it completly. Essentially doubling the amount of data
needed to be read or written.
- Rotating disks are faster at low sector addresses, allocating high
parity will slow down disks that could be instead faster.
* Use a memory mapped file to read the content file
- Tried. No speed gain.
* Allow multiple parity files and to coexist with data
in the same disk.
This is possible if the data in the same disk uses parity addresses not
contained in the parity file present in the same disk.
+ It's a nice trick. The disk containing parity, will have less space available,
and then it will need less parity, resolving the problem of the parity disk being too small.
+ We can also think at an automated parity files naming and creation, removing
the need of the user to specify that. We can also completely remove the
concept of parity drive, automatically allocating parity in the most free data drives.
- It won't be nice to have the program to automatically
choose where to create the parity, because the choice cannot be optimal.
With a dedicated disk manually chosen, it's instead optimal.
+ We can limit this coexist possibility only to latest parity file,
allowing the user to choose where to put it.
- It won't work with disks of different size.
Suppose to have all disks of size N, with only one of size M>N.
To fully use the M space, you can allocate a full N parity in such disk,
but the remaining space will also need additional parity in the other disks,
in fact requiring a total of M parity for the array.
In the end, we cannot avoid that the first biggest disk added is fully
dedicated to parity, even if it means to leave some space unused.
* Directly access disks for parity skipping the filesystem layer
- No real performance or space gain compared to a custom filesystem configuration like:
mkfs.ext3 -i 16777216 -m0 -O ^dir_index,large_file,sparse_super /dev/sdX1
See: https://sourceforge.net/p/snapraid/discussion/1677233/thread/9c0ef324/?limit=25
* Allow to specify more than one disk directories to cover the case of multi partitions.
Different partitions have duplicate inode. The only way to support this is to
add also a kind of device_id, increasing the memory required.
But it should be only few bits for each file. So, it should be manageable.
A lot of discussions about this feature :)
https://sourceforge.net/p/snapraid/discussion/1677233/thread/b2cd9385/
- The only benefit is to distribute better the data. This could help the recovery process,
in case of multiple failures. But no real usability or functionality benefit in the normal
case.
* https://sourceforge.net/p/snapraid/discussion/1677233/thread/2cb97e8a/
Have two hashes for each file. One for the first segment, that may use only a part of the first parity block.
And a second hash that takes care of the final segment, also using only part of a parity block.
Intermediate blocks can be handled like now.
The first and last segment can use only a part of the parity block, sharing it with other files,
and then allowing big parity blocks.
+ Big parity block, like 1MB, and small file allocation, like 4KB.
- It won't be possible to copy hash info from one disk to another, as copied files
may have a different block splitting. Copied file should be allocated with the same exact
splitting.
- Dup detection can be handled with a dedicated hash covering the full file. But increasing
the number of hash for each file to three.
- No way to handle block import.
* Checks if splitting hash/parity computation in 4K pages
can improve speed in sync. That should increase cache locality,
because we read the data two times for hash and parity,
and if we manage to keep it in the cache, we should save time.
- We now hash first the faster disks, and this could
reduce performance as we'll have to wait for all disks.
* Enable storing of creation time NTFS, crtime/birth time EXT4.
But see: http://unix.stackexchange.com/questions/50177/birth-is-empty-on-ext4
coreutils stat has an example, but it doesn't work in Linux (see lib/stat-time.h)
- Not supported in Linux.
* In the content file save the timestamp of the parity files.
If they do not match, stop the processing. If they do not match, stop the processing.
This can be done to avoid to use not synchronized parity and content files, This can be done to avoid to use not syncronized parity and content files,
resulting in wrong data. resulting in wrong data.
But if the sync process is killed we need a way to resynchronize them. But if the sync process is killed we need a way to resyncronize them.
Or maybe we should allow parity newer than content, but not viceversa. Or maybe we should allow parity never than content, but not viceversa.
- The corner cases are too many. A fixed parity may be never.
A someway modified content may be never. So, the time is not really significant. - Major
* Use Async IO for Linux (libaio). * Use Async IO for Linux (libaio).
See thread: https://sourceforge.net/p/snapraid/discussion/1677233/thread/a300a10b/ See thread: https://sourceforge.net/p/snapraid/discussion/1677233/thread/a300a10b/
Docs at: http://www.fsl.cs.sunysb.edu/~vass/linux-aio.txt
- Implemented for scrub in the "libaio" branch, but it's slower of
about 20% in my machine.
* Allow to put parity directly into the underline block device without the need * Triple parity also called RAID-TP. We can implement it in a compatible way
of any filesystem. with the existing RAID-5 and RAID-6 definining a new r-parity file.
That would allow to increase a lot the free space for parity. See http://blogs.oracle.com/ahl/entry/triple_parity_raid_z and
We can implement some kind of filesystem detection to avoid to overwrite an already http://thread.gmane.org/gmane.linux.raid/34195/focus=34236
existing filesystem.
- Still risky if stuffs go wrong.
- In Linux with largefile4 there is only a very small amount of space wasted.
In the order of 0.01%. Not really worth to do it.
- With NTFS the saving is also limited, because the "reserved" MFT of 12.5% is
not really exclusively reserved, but can be used also for normal files,
when all the remaining space is filled.
* The data could be compressed before processing, resulting in parity block of * The data could be compressed before processing, resulting in parity block of fixed size,
fixed size, but matching different data block sizes. but matching different data block sizes.
The complexity is that a file blocks will have to be allocated at runtime, The complexity is that a file blocks will have to be allocated at runtime,
and you may run out of them in the middle of the processing. and you may run out of them in the middle of the processing.
We need also a way to compress a stream until the compressed data reach the We need also a way to compress a stream until the compressed data reach the
block size, but no more, and then start a new block. block size, but no more, and then start a new block.
For each block, we'll have also to store. "size_uncompressed", "size_compressed", For each block, we'll have also to store. "size_uncompressed", "size_compressed",
"hash". "hash".
- It will be too slow.
- Not addressing the problem of a lot of small files, as still one block will be
allocated for each file.
* Uses different block size for parity and file allocation. Rejected TODO
We can use a big size, like 1MB for parity allocation and hash computation, =============
and at the same time using a 4K blocks for files allocation.
This means that a parity blocks may contain more than one file.
- We'll have to drop the dup and import feature,
because it won't be possible anymore to compare the hash of files,
as it would depend also on the start address inside the parity block.
- When a hash fail, it won't be possible to tell which file is really
broken, because more file may share the same parity block.
* Have special parity blocks containing the last blocks of more files This is a list of rejected TODO items.
until it's filled up.
For such parity blocks, we'll have more than one hash. One for each
file contained.
- Parity will be too fragmented, because we'll have parity blocks
containing the last blocks of many files.
* In "pool" for Windows, and for unique directories a junction to the
directory could be used, avoiding to use symlinks to files.
This allows to overcome the problem of sharing symlinks.
- It would work, in fact it would work too well. The problem is that
Windows will treat the junction as the real directory, like *really*
deleting its content from Explorer pressing "del" and also from the
command line with "rd". Too dangerous.
* When fixing, before overwriting the present file, make a copy of it just in * When fixing, before overwriting the present file, make a copy of it just in
case that the original file cannot be completely recovered. case that the original file cannot be completely recovered.
@ -360,7 +119,7 @@ Anyway, considering the typical use, it's not really relevant.
* In the import list, uses also all the blocks in the array. * In the import list, uses also all the blocks in the array.
But we must cover the case of bad blocks. Likely we can just check the But we must cover the case of bad blocks. Likely we can just check the
hash after reading, and in case, skip it, and retry with another copy. hash after reading, and in case, skip it, and retry with another copy.
- It will work only for duplicate files. Not really worth to do it. - It will work only for duplicate files. Not really worth do to it.
* Save the content file in compressed .gz format to save space. * Save the content file in compressed .gz format to save space.
- Compression is too slow. Even using the very fast lzo. - Compression is too slow. Even using the very fast lzo.
@ -391,43 +150,11 @@ sys 0m4.398s
data doesn't overlap, do not recompute it. data doesn't overlap, do not recompute it.
- It's going to work only in RAID5 mode and only in special cases. - It's going to work only in RAID5 mode and only in special cases.
* Implements a multithread sync command to share HASH and RAID computations * Implements a multithread sync command.
to different CPUs. - At now it's questionable if it will result in a performance improvment.
- At now it's questionable if it will result in a performance improvement.
The murmur3 hash, and the RAID5/6 computations are so fast that even a single The murmur3 hash, and the RAID5/6 computations are so fast that even a single
thread should be able to do them. thread should be able to do them.
Use the "snapraid -T" command to see the speed. Use the "snapraid -T" comment to see the speed.
Also, all the file operations are already done in background by the OS,
so no improvement is expect from this side.
* In the repair() function the heuristic to detect if we recovered after the sync,
can be extended to all the previous blocks, because we always proceed in block
order during a sync.
So, if for a block we can detect that we recovered using updated parity data,
also for all the previous blocks this is true.
Anyway, the case where this information could be useful should be present
only if changes are committed after an aborted sync.
- No real advantage on that, beside some speed gain in fix.
The risk would be instead to miss some recovery opportunity.
So, makes sense to have it a little slower but trying any
possible recovery strategy.
* Extend haspdeep to support the SnapRAID hash.
- Not possible, because now SnapRAID uses a hash seed that makes the hash unique
for each array
https://github.com/jessek/hashdeep/
https://sourceforge.net/p/snapraid/discussion/1677233/thread/90b0e9b2/?limit=25
* Uses a separated file for storing hashes, to allow to use a memory
mapped file to decrease memory utilization.
- Now it's expected to have machines with big memory.
The file can contains hashes stored in the same order they are accessed
in sync/check/scrub.
+ A lot less memory utilization
- It will be slow in --pre-hash as the files are accessed in another order,
but not much slow.
- How to handle multiple .content file copy ? When working we can have
only a single file. When storing the .content we'll have to copy it
in all the places.
* Can we mix the existing and new approach ? We can create this
hash file at startup in a memory mapped "temporary" file.
It may take some time to create it, but then it will be fast.
See: https://sourceforge.net/p/snapraid/discussion/1677233/thread/cdea773f/

View file

@ -1,7 +1,7 @@
dnl @synopsis AC_CHECK_CC_OPT(flag, ifyes, ifno) dnl @synopsis AC_CHECK_CC_OPT(flag, ifyes, ifno)
dnl dnl
dnl Shows a message as like "checking whether gcc accepts flag ... no" dnl Shows a message as like "checking wether gcc accepts flag ... no"
dnl and executes ifyes or ifno. dnl and executess ifyes or ifno.
AC_DEFUN([AC_CHECK_CC_OPT], AC_DEFUN([AC_CHECK_CC_OPT],
[ [

View file

@ -3,10 +3,8 @@
echo "Generating build information using autoreconf" echo "Generating build information using autoreconf"
# All is done by autoreconf # All is done by autoreconf
autoreconf -f -i autoreconf -i
# Run configure for this platform # Run configure for this platform
echo "Now you are ready to run ./configure" echo "Now you are ready to run ./configure"
# Remove backup files created by autoreconf
rm -f config.guess~ config.h.in~ config.sub~ configure~ install-sh~

View file

@ -1,33 +0,0 @@
#!/bin/sh
#
SRCDIR="${srcdir:-$(dirname "$0")}"
if [ -f "$SRCDIR/.version" ]; then
# Get version from the .version file
VERSION=$(cat "$SRCDIR/.version")
fi
if [ -z "$VERSION" ] && [ -e "$SRCDIR/.git" ]; then
# Get version from git tags, removing the 'v' prefix
VERSION=$(git -C "$SRCDIR" describe --match 'v*' 2>/dev/null | sed 's/^v//')
fi
if [ -z "$VERSION" ] && [ -e "$SRCDIR/.git" ]; then
# Fall back to short commit hash
VERSION=0-$(git -C "$SRCDIR" rev-parse --short HEAD 2>/dev/null)
fi
if [ -z "$VERSION" ]; then
# No version, but still use a number
VERSION="0"
fi
# Apply common rules to all outputs:
# - Remove "-" at the end
# - Replace "rc-" with "rc"
# - Replace "beta-" with "beta"
# - Replace all remaining dashes with "."
VERSION=$(echo "$VERSION" | sed 's/-$//; s/rc-/rc/g; s/beta-/beta/g; s/-/./g')
printf '%s' "$VERSION"

1710
check.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,522 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2026 Andrea Mazzoleni
#ifndef APP_H
#define APP_H
#include "os/os.h"
/**
* Include list support to have tommy_node.
*/
#include "tommyds/tommylist.h"
#define STATIC_ASSERT(name, cond) typedef char static_assert_ ## name[(cond) ? 1 : -1]
#define EDATA (-1) /**< Silent data corruption. */
#define EINTERNAL EFAULT /**< Internal assertion failed. */
#define ESOFT EINVAL /**< Software error, like permission denied. */
#define EUSER EINVAL /**< Invalid value specified by the user. */
#define EEXTERNAL EINVAL /**< Invalid external interface behaviour. */
#define ECONTENT EINVAL /**< Invalid content file. */
#define EENVIRONMENT EINVAL /**< Invalid physical environment, like temperature too high. */
#define ESYSLOG EINVAL /**< Syslog error. */
/**
* Basic block position type.
*/
typedef uint64_t block_off_t;
/**
* Basic data position type.
* It's signed as file size and offset are usually signed.
*/
typedef int64_t data_off_t;
/**
* Another name for link() to avoid confusion with local variables called "link".
*/
static inline int hardlink(const char* a, const char* b)
{
return link(a, b);
}
/**
* Get the device UUID.
* Return 0 on success.
*/
int devuuid(uint64_t device_id, const char* device_path, char* uuid, size_t size);
/**
* Filesystem identity for directory boundary checks.
*/
struct fsidentity {
uint64_t device; /**< Device identifier (st_dev). */
uint64_t mnt_id; /**< Mount identifier (stx_mnt_id or 0). */
uint64_t subvol; /**< Subvolume identifier (stx_subvol or 0). */
};
/**
* Get the filesystem identity of a path.
*
* The caller already provides the normal stat information.
* This function must NOT repeat lstat()/stat() for normal metadata.
*
* mnt_id and subvol are set to zero when unavailable.
*
* Return 0 on success, -1 on error.
*/
int fsidentity(const char* path, const struct stat* st, struct fsidentity* identity);
/**
* Check if the underline file-system support persistent inodes.
* Return -1 on error, 0 on success.
*/
int fsinfo(const char* path, int* has_persistent_inode, int* has_syncronized_hardlinks, uint64_t* total_space, uint64_t* free_space, char* fstype, size_t fstype_size, char* fslabel, size_t fslabel_size);
/**
* Where snapshot are accessible
*/
#define SNAPSHOT_CONTAINER ".snapraid"
/**
* Snapshots names
*/
#define SNAPSHOT_PENDING "pending"
#define SNAPSHOT_STABLE "stable"
#define SNAPSHOT_SCAN "scan"
#define SNAPSHOT_RETIRING_SUFFIX ".retiring"
/**
* Snapshots context
*/
struct fssnapshot_struct {
/**
* Filesystem magic number
* 0 if no snapshot support
*/
uint32_t magic;
/**
* Root directory of the volume/dataset mountpoint.
* It ALWAYS terminates with /
* - Btrfs/Bcachefs: subvolume root (canonical path via realpath)
* - ZFS: dataset mountpoint (canonical path via realpath)
* - Windows: volume mountpoint (via GetVolumePathName)
*/
char root_dir[PATH_MAX];
/**
* Directory where snapshots are accessible as subdirectories.
* It ALWAYS terminates with /
* - Btrfs/Bcachefs: real directory (e.g. <root>/.snapraid/)
* - ZFS: virtual directory (e.g. <root>/.zfs/snapshot/)
* - Windows: symlink container directory (e.g. <root>/.snapraid/)
*/
char snapshot_dir[PATH_MAX];
/**
* Data directory relative to root_dir in snapshots.
*
* It NEVER starts with '/'.
* It is empty if the configured data directory is exactly root_dir.
* If non-empty, it ALWAYS terminates with '/'.
* - Unix: relative suffix computed from the realpath() canonical representation
* - Windows: relative suffix computed from the GetFullPathNameW() absolute representation without resolving reparse points
*/
char sub_dir[PATH_MAX];
/*
* Dataset name for ZFS (e.g. "pool/data")
* or VolumeName in Windows (e.g. "\\?\Volume{guid}\").
* Empty string for filesystems where not applicable.
*/
char dataset[PATH_MAX];
};
/**
* Initialize snapshot context from an arbitrary path.
*
* @param dir Path inside the filesystem (must end with '/')
* @param fss Output snapshot context
* @return 0 on success, 1 if snapshots are unsupported, -1 on failure
*/
int fssnapshot_mount(const char* dir, struct fssnapshot_struct* fss);
/**
* Unmount the snapshots.
*
* Required in Windows to remove the temporary symlinks.
*
* @param fss Snapshot context
*/
void fssnapshot_unmount(const struct fssnapshot_struct* fss);
/**
* Stat the snapshot directory.
*
* @param fss Snapshot context
* @param name Snapshot name
* @param st Set the stat info
* @return 0 on success, -1 on failure
*/
int fssnapshot_stat(struct fssnapshot_struct* fss, const char* name, struct stat* st);
/**
* Create a snapshot of the filesystem root/dataset.
*
* @param fss Snapshot context
* @param name Snapshot name
* @return 0 on success, -1 on failure
*/
int fssnapshot_create(const struct fssnapshot_struct* fss, const char* name);
/**
* Delete a snapshot.
*
* @param fss Snapshot context
* @param name Snapshot name
* @return 0 on success, -1 on failure
*/
int fssnapshot_delete(const struct fssnapshot_struct* fss, const char* name);
/**
* Rename a snapshot.
*
* @param fss Snapshot context
* @param old_name Existing snapshot name
* @param new_name New snapshot name
* @return 0 on success, -1 on failure
*/
int fssnapshot_rename(const struct fssnapshot_struct* fss, const char* old_name, const char* new_name);
/**
* Replace a snapshot while preserving the previous destination until the new one is published.
*
* An interrupted replacement is recovered automatically by fssnapshot_mount().
*
* @param fss Snapshot context
* @param old_name Existing source snapshot name
* @param new_name Destination snapshot name
* @return 0 on success, -1 on failure
*/
int fssnapshot_replace(struct fssnapshot_struct* fss, const char* old_name, const char* new_name);
/**
* Get the path where a logical snapshot is accessible.
*
* @param fss Snapshot context
* @param name Logical snapshot name
* @param path Output path
* @param path_size Size of path
* @return 0 on success, -1 on failure
*/
int fssnapshot_path(const struct fssnapshot_struct* fss, const char* name, char* path, size_t path_size);
/**
* Log file.
*
* This stream if fully buffered.
*
* If no log file is selected, it's 0.
*/
extern FILE* stdlog;
/**
* Exit codes for testing.
*/
extern int exit_success;
extern int exit_failure;
extern int exit_sync_needed;
extern int exit_degraded;
#undef EXIT_SUCCESS
#undef EXIT_FAILURE
#define EXIT_SUCCESS exit_success
#define EXIT_FAILURE exit_failure
#define EXIT_SYNC_NEEDED exit_sync_needed
#define EXIT_DEGRADED exit_degraded
/**
* Standard SMART attributes.
*/
#define SMART_REALLOCATED_SECTOR_COUNT 5
#define SMART_POWER_ON_HOURS 9
#define SMART_POWER_CYCLE_COUNT 12
#define SMART_UNCORRECTABLE_ERROR_CNT 187
#define SMART_COMMAND_TIMEOUT 188
#define SMART_CURRENT_PENDING_SECTOR 197
#define SMART_OFFLINE_UNCORRECTABLE 198
#define SMART_START_STOP_COUNT 4
#define SMART_POWER_ON_HOURS 9
#define SMART_AIRFLOW_TEMPERATURE_CELSIUS 190
#define SMART_LOAD_CYCLE_COUNT 193
#define SMART_TEMPERATURE_CELSIUS 194
/**
* Flags returned by smartctl via exit code
*/
#define SMART_FLAGS 256
/**
* Counts command, transport, or controller-level errors reported by the device.
* These reflect failed I/O operations not directly caused by media defects
* (for example interface, firmware, or power-related errors).
* This counter is cumulative and never resets to zero, even if the underlying
* error condition is resolved.
*/
#define SMART_ERROR_PROTOCOL 257
/**
* Counts media-level errors where data could not be reliably read or written.
* These indicate actual storage surface or flash failures and may imply data loss.
* This counter is cumulative and never resets to zero, even if the underlying
* error condition is resolved.
*/
#define SMART_ERROR_MEDIUM 258
/**
* Unified Wear Level Metric (0-100)
*
* Represents the remaining life of an SSD.
* - 0: Brand new drive (0% wear).
* - 100: Drive has reached or exceeded its manufacturer-rated design life.
*/
#define SMART_WEAR_LEVEL 259
/**
* SMART attributes count.
*/
#define SMART_COUNT 260
/**
* NVME custom SMART attributes
*
* The numbers are just arbitrary to put them in unused space
*/
#define SMART_NVME_CRITICAL_WARNING 100
#define SMART_NVME_AVAILABLE_SPARE 101
#define SMART_NVME_DATA_UNITS_READ 102
#define SMART_NVME_DATA_UNITS_WRITTEN 103
#define SMART_NVME_HOST_READ_COMMANDS 104
#define SMART_NVME_HOST_WRITE_COMMANDS 105
#define SMART_NVME_CONTROLLER_BUSY_TIME 106
#define SMART_NVME_UNSAFE_SHUTDOWNS 107
#define SMART_NVME_WARNING_COMP_TEMPERATURE_TIME 108
#define SMART_NVME_CRITICAL_COMP_TEMPERATURE_TIME 109
/**
* Info attributes.
*/
#define INFO_SIZE 0 /**< Size in bytes. */
#define INFO_ROTATION_RATE 1 /**< Rotation speed. 0 for SSD. */
/**
* Info attributes count.
*/
#define INFO_COUNT 2
/**
* Max number of ignored smart attributes
*/
#define SMART_IGNORE_MAX 4
/**
* Flags returned by smartctl.
*/
#define SMARTCTL_FLAG_UNSUPPORTED (1 << 0) /**< Device not recognized, requiring the -d option. */
#define SMARTCTL_FLAG_OPEN (1 << 1) /**< Device open or identification failed. */
#define SMARTCTL_FLAG_COMMAND (1 << 2) /**< Some SMART or ATA commands failed. This is a common error, also happening with full info gathering. */
#define SMARTCTL_FLAG_FAIL (1 << 3) /**< SMART status check returned "DISK FAILING". */
#define SMARTCTL_FLAG_PREFAIL (1 << 4) /**< We found prefail Attributes <= threshold. */
#define SMARTCTL_FLAG_PREFAIL_LOGGED (1 << 5) /**< SMART status check returned "DISK OK" but we found that some (usage or prefail) Attributes have been <= threshold at some time in the past. */
#define SMARTCTL_FLAG_ERROR_LOGGED (1 << 6) /**< The device error log contains records of errors. */
#define SMARTCTL_FLAG_SELFERROR_LOGGED (1 << 7) /**< The device self-test log contains records of errors. */
/**
* SMART max attribute name or value length.
*/
#define SMART_MAX 128
/**
* Max smartctl custom option length.
*/
#define SMARTCTL_MAX 512
/**
* Smart ignore structure.
*/
struct smartignore_struct {
int attr_index; /**< 0 if not set */
char attr_name[SMART_MAX]; /**< Empty if not set */
};
/**
* Value for unassigned SMART attribute.
*/
#define SMART_UNASSIGNED 0xFFFFFFFFFFFFFFFFULL
/**
* SMART Attribute flags
*/
#define SMART_ATTR_TYPE_PREFAIL 1
#define SMART_ATTR_TYPE_OLDAGE 2
#define SMART_ATTR_UPDATE_ALWAYS 4
#define SMART_ATTR_UPDATE_OFFLINE 8
#define SMART_ATTR_WHEN_FAILED_NOW 16
#define SMART_ATTR_WHEN_FAILED_PAST 32
#define SMART_ATTR_WHEN_FAILED_NEVER 64
struct smart_attr {
char name[SMART_MAX]; /**< SMART attribute name. */
uint64_t raw; /**< SMART attributes raw. It can be SMART_UNASSIGNED. */
uint64_t norm; /**< SMART attributes normalized. It can be SMART_UNASSIGNED even if raw is not. */
uint64_t worst; /**< SMART attributes worst. It can be SMART_UNASSIGNED even if raw/norm is not. */
uint64_t thresh; /**< SMART attributes threshold. It can be SMART_UNASSIGNED even if raw/norm/worst is not. */
int flags; /**< SMART_ATTR_* flags */
};
/**
* Power mode
*/
#define POWER_STANDBY 0
#define POWER_ACTIVE 1
#define POWER_UNKNOWN -1
struct devinfo_struct {
uint64_t device; /**< Device ID. */
char name[PATH_MAX]; /**< Name of the disk combined with the split index if any */
char mount[PATH_MAX]; /**< Mount point or other contained directory. */
char smartctl[SMARTCTL_MAX]; /**< Custom option for smartctl. Empty means auto. */
char smartctl_info[SMARTCTL_MAX]; /**< Info options for smartctl. Empty means -a. */
struct smartignore_struct smartignore[SMART_IGNORE_MAX]; /**< Attributes to ignore */
char file[PATH_MAX]; /**< File device. */
#ifdef _WIN32
char wfile[PATH_MAX]; /**< File device in Windows format. Like \\.\PhysicalDriveX, or \\?\Volume{X}. */
#endif
struct devinfo_struct* parent; /**< Pointer at the parent if any. */
int is_array; /**< 1 if this is an array disk (data or parity), 0 if extra disk. */
struct devinfo_struct* split; /**< Pointer at first split if this one is not the first. */
struct smart_attr smart[SMART_COUNT]; /**< All smart values. */
uint64_t info[INFO_COUNT]; /**< Informational attributes not related to SMART telemetry. */
uint64_t access_stat; /**< Access stat info. */
char serial[SMART_MAX]; /**< Serial number. */
char family[SMART_MAX]; /**< Family. */
char model[SMART_MAX]; /**< Model. */
char interf[SMART_MAX]; /**< Interface of the device: ata, sata, pata, nvme, usb */
int power; /**< POWER mode. */
#if HAVE_THREAD
thread_id_t thread;
#endif
tommy_node node;
};
typedef struct devinfo_struct devinfo_t;
void device_name_set(devinfo_t* dev, const char* name, int index);
#define DEVICE_LIST 0
#define DEVICE_DOWN 1
#define DEVICE_UP 2
#define DEVICE_SMART 3
#define DEVICE_PROBE 4
#define DEVICE_DOWNIFUP 5
/**
* Sync filesystems associated with the "high" level devices.
* Return 0 on success, -1 on error.
*/
int devsync(tommy_list* high);
/**
* Query all the "high" level devices and produce a list of "low" level devices.
*
* The passed "low" device list must be already initialized.
*/
int devquery(tommy_list* high, tommy_list* low);
/**
* Execute an operation on the "low" level devices.
*/
int devrun(tommy_list* low, int operation);
/**
* Fill with fake data the device list.
*/
int devtest(tommy_list* high, tommy_list* low, int operation);
/**
* Query all the "low" devices and log their unique identifiers
*/
int devmap(void);
/**
* Get the ambient temperature in degree
*
* Return 0 if not available.
*/
int ambient_temperature(void);
/**
* Size of the spaceholder file for Windows to avoid the message of low disk space
*/
#define WINDOWS_SPACEHOLDER_SIZE (256 * 1024 * 1024)
/****************************************************************************/
/* app */
/**
* Initializes the application.
*/
void app_init(void);
/**
* Deinitializes the application.
*/
void app_done(void);
/**
* Default paths.
*/
void app_default_conf(char* dst, size_t dst_size, const char* argv0);
/**
* Signal handler.
*/
void app_signal_handler(int signum);
/****************************************************************************/
/* machine */
#define MACHINEINFO_MAX 256
/**
* Host machine and CPU information.
*/
struct machineinfo_struct {
char cpu_brand[MACHINEINFO_MAX]; /**< CPU model brand name. */
char cpu_vendor[MACHINEINFO_MAX]; /**< CPU vendor string (e.g. GenuineIntel, AuthenticAMD). */
char cpu_arch[MACHINEINFO_MAX]; /**< CPU architecture string. */
char cpu_clock[MACHINEINFO_MAX]; /**< CPU clock frequency description. */
unsigned cpu_family; /**< CPU family id. */
unsigned cpu_model; /**< CPU model id. */
unsigned cpu_stepping; /**< CPU stepping id. */
unsigned cpu_cores_physical; /**< Number of physical CPU cores (0 if unavailable). */
unsigned cpu_cores_logical; /**< Number of logical CPU threads (0 if unavailable). */
uint64_t cache_l1_data; /**< L1 data cache in bytes (0 if unavailable). */
uint64_t cache_l1_instruction; /**< L1 instruction cache in bytes (0 if unavailable). */
uint64_t cache_l2; /**< L2 cache in bytes (0 if unavailable). */
uint64_t cache_l3; /**< L3 cache in bytes (0 if unavailable). */
uint64_t memory_total_bytes; /**< Total system RAM in bytes (0 if unavailable). */
uint32_t memory_page_size; /**< Page size in bytes (0 if unavailable). */
char os_name[MACHINEINFO_MAX]; /**< Operating system name and kernel version. */
char os_distribution[MACHINEINFO_MAX]; /**< Operating system distribution name. */
char system_model[MACHINEINFO_MAX]; /**< Motherboard or system model name. */
char hypervisor[MACHINEINFO_MAX]; /**< Hypervisor name (empty if bare metal). */
};
/**
* Query host machine information.
*/
void machineinfo(struct machineinfo_struct* info);
#endif

View file

@ -1,75 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2016 Andrea Mazzoleni
#include "os/portable.h"
#include "bw.h"
void bw_init(struct snapraid_bw* bw, uint64_t limit)
{
bw->limit = limit;
bw->total = 0;
bw->start = os_tick_ms();
#if HAVE_THREAD
thread_mutex_init(&bw->lock);
#endif
}
void bw_done(struct snapraid_bw* bw)
{
#if HAVE_THREAD
thread_mutex_destroy(&bw->lock);
#else
(void)bw;
#endif
}
void bw_limit(struct snapraid_bw* bw, uint64_t bytes)
{
if (!bw || bw->limit == 0)
return;
#if HAVE_THREAD
thread_mutex_lock(&bw->lock);
#endif
uint64_t start = bw->start;
uint64_t now = os_tick_ms();
uint64_t elapsed = now - start;
uint64_t done;
uint64_t eta;
bw->total += bytes;
done = bw->total;
eta = (done / bw->limit) * 1000 + (done % bw->limit) * 1000 / bw->limit;
/*
* To prevent accumulating unlimited credit during long pauses
* (such as CPU-bound hashing or metadata scanning), we cap the
* maximum accumulated credit to 10 seconds.
* If the elapsed time is more than 10 seconds ahead of the target ETA,
* we advance the start time to align the credit to exactly 10 seconds.
*/
if (elapsed > eta + 10000) {
bw->start = now - eta - 10000;
elapsed = eta + 10000;
}
/*
* Sleep inside the lock to serialize delays across all worker threads.
*
* When multiple threads perform IO in parallel, holding the lock
* during sleep ensures each thread only sleeps for its own incremental
* delay, while waiting threads wait on the mutex and accurately measure
* the elapsed time once they acquire the lock.
*/
if (eta > elapsed) {
os_usleep((eta - elapsed) * 1000);
}
#if HAVE_THREAD
thread_mutex_unlock(&bw->lock);
#endif
}

View file

@ -1,40 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2016 Andrea Mazzoleni
#ifndef BW_H
#define BW_H
#include "state.h"
#include "support.h"
/**
* Bandwidth limiting
*/
struct snapraid_bw {
uint64_t limit; /**< Bandwidth limit in bytes per second */
uint64_t total; /**< Remaining bytes allowed in current second */
uint64_t start; /**< Time when to reset the bandwidth counter */
#if HAVE_THREAD
thread_mutex_t lock; /**< Mutex protecting bw fields */
#endif
};
/**
* Initialize the bandwidth limit
*/
void bw_init(struct snapraid_bw* bw, uint64_t limit);
/**
* Destroy the bandwidth limit
*/
void bw_done(struct snapraid_bw* bw);
/**
* Limit IO bandwidth to stay within the configured limit.
* If no limit is set, returns immediately.
* Otherwise sleeps as needed to maintain the rate limit.
*/
void bw_limit(struct snapraid_bw* bw, uint64_t bytes);
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,8 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
/* enable the --test-run option */
#define HAVE_CHECKER 1
#include "snapraid.c"

File diff suppressed because it is too large Load diff

View file

@ -1,503 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
#include "os/portable.h"
#include "util.h"
#include "elem.h"
#include "state.h"
#include "parity.h"
#include "handle.h"
#include "io.h"
#include "raid/raid.h"
/****************************************************************************/
/* dry */
static const char* es(int err)
{
if (is_hw(err))
return "error_io";
else
return "error";
}
static void dry_data_reader(struct snapraid_worker* worker, struct snapraid_task* task)
{
struct snapraid_io* io = worker->io;
struct snapraid_state* state = io->state;
struct snapraid_handle* handle = worker->handle;
struct snapraid_disk* disk = handle->disk;
block_off_t blockcur = task->position;
unsigned char* buffer = task->buffer;
int ret;
/* if the disk position is not used */
if (!disk) {
/* use an empty block */
memset(buffer, 0, state->block_size);
task->state = TASK_STATE_DONE;
return;
}
/* get the block */
task->block = fs_par2block_find(disk, blockcur);
/* if the block is not used */
if (!block_has_file(task->block)) {
/* use an empty block */
memset(buffer, 0, state->block_size);
task->state = TASK_STATE_DONE;
return;
}
/* get the file of this block */
task->file = fs_par2file_get(disk, blockcur, &task->file_pos);
/* if the file is different than the current one, close it */
if (handle->file != 0 && handle->file != task->file) {
/* keep a pointer at the file we are going to close for error reporting */
struct snapraid_file* report = handle->file;
ret = handle_close(handle);
if (ret == -1) {
/* LCOV_EXCL_START */
/*
* This one is really an unexpected error, because we are only reading
* and closing a descriptor should never fail
*/
log_tag("%s::%s:%s: Close error. %s.\n", es(errno), disk->name, esc_tag(report->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
log_fatal(errno, "Stopping at block %" PRIu64 "\n", blockcur);
if (is_hw(errno)) {
task->state = TASK_STATE_IOERROR;
} else {
task->state = TASK_STATE_ERROR;
}
return;
/* LCOV_EXCL_STOP */
}
}
ret = handle_open(handle, task->file, state->file_mode, 0);
if (ret == -1) {
log_tag("%s:%" PRIu64 ":%s:%s: Open error. %s.\n", es(errno), blockcur, disk->name, esc_tag(task->file->sub), strerror(errno));
if (is_hw(errno)) {
/* LCOV_EXCL_START */
log_fatal_errno(errno, disk->name);
log_fatal(errno, "Stopping at block %" PRIu64 "\n", blockcur);
task->state = TASK_STATE_IOERROR;
return;
/* LCOV_EXCL_STOP */
}
task->state = TASK_STATE_ERROR_CONTINUE;
return;
}
task->read_size = handle_read(handle, task->file_pos, buffer, state->block_size, 0);
if (task->read_size == -1) {
log_tag("%s:%" PRIu64 ":%s:%s: Read error at position %" PRIu64 ". %s.\n", es(errno), blockcur, disk->name, esc_tag(task->file->sub), task->file_pos, strerror(errno));
if (is_hw(errno)) {
/* LCOV_EXCL_START */
log_fatal_errno(errno, disk->name);
task->state = TASK_STATE_IOERROR_CONTINUE;
return;
/* LCOV_EXCL_STOP */
}
task->state = TASK_STATE_ERROR_CONTINUE;
return;
}
/* store the path of the opened file */
pathcpy(task->path, sizeof(task->path), handle->path);
task->state = TASK_STATE_DONE;
}
static void dry_parity_reader(struct snapraid_worker* worker, struct snapraid_task* task)
{
struct snapraid_io* io = worker->io;
struct snapraid_state* state = io->state;
struct snapraid_parity_handle* parity_handle = worker->parity_handle;
unsigned level = parity_handle->level;
block_off_t blockcur = task->position;
unsigned char* buffer = task->buffer;
int ret;
/* read the parity */
ret = parity_read(parity_handle, blockcur, buffer, state->block_size);
if (ret == -1) {
log_tag("parity_%s:%" PRIu64 ":%s: Read error. %s.\n", es(errno), blockcur, lev_config_name(level), strerror(errno));
if (is_hw(errno)) {
/* LCOV_EXCL_START */
log_fatal_errno(errno, lev_config_name(level));
task->state = TASK_STATE_IOERROR_CONTINUE;
return;
/* LCOV_EXCL_STOP */
}
task->state = TASK_STATE_ERROR_CONTINUE;
return;
}
task->state = TASK_STATE_DONE;
}
static int state_dry_process(struct snapraid_state* state, struct snapraid_parity_handle* parity_handle, block_off_t blockstart, block_off_t blockmax)
{
struct snapraid_io io;
struct snapraid_handle* handle;
unsigned diskmax;
block_off_t blockcur;
unsigned j;
unsigned buffermax;
int ret;
data_off_t countsize;
block_off_t countpos;
block_off_t countmax;
unsigned soft_error;
unsigned io_error;
unsigned l;
unsigned* waiting_map;
unsigned waiting_mac;
handle = handle_mapping(state, &diskmax);
/* we need 1 * data + 2 * parity */
buffermax = diskmax + 2 * state->level;
/* initialize the io threads */
io_init(&io, state, state->opt.io_cache, buffermax, handle, diskmax, 0, dry_data_reader, 0, parity_handle, state->level, 0, dry_parity_reader, 0);
/* possibly waiting disks */
waiting_mac = diskmax > RAID_PARITY_MAX ? diskmax : RAID_PARITY_MAX;
waiting_map = nalloc_nofail(waiting_mac, sizeof(unsigned));
soft_error = 0;
io_error = 0;
/* drop until now */
state_usage_waste(state);
countmax = blockmax - blockstart;
countsize = 0;
countpos = 0;
blockcur = blockstart;
int alert = state_progress_begin(state, blockstart, blockmax, countmax);
if (alert > 0)
goto end;
if (alert < 0)
goto bail;
/* start all the worker threads */
io_start(&io, blockstart, blockmax, 0);
while (1) {
void** buffer;
/* go to the next block */
blockcur = io_read_next(&io, &buffer);
if (blockcur >= blockmax)
break;
/* until now is scheduling */
state_usage_sched(state);
/* for each disk, process the block */
for (j = 0; j < diskmax; ++j) {
struct snapraid_task* task;
ssize_t read_size;
struct snapraid_block* block;
struct snapraid_disk* disk;
unsigned diskcur;
/* until now is misc */
state_usage_misc(state);
/* get the next task */
task = io_data_read(&io, &diskcur, waiting_map, &waiting_mac);
/* until now is disk */
state_usage_disk(state, handle, waiting_map, waiting_mac);
/* get the task results */
disk = task->disk;
block = task->block;
read_size = task->read_size;
/* if the disk position is not used */
if (!disk)
continue;
state_usage_file(state, disk, task->file);
/* if the block is not used */
if (!block_has_file(block))
continue;
/* handle error conditions */
if (task->state == TASK_STATE_IOERROR) {
/* LCOV_EXCL_START */
++io_error;
goto bail;
/* LCOV_EXCL_STOP */
}
if (task->state == TASK_STATE_ERROR) {
/* LCOV_EXCL_START */
++soft_error;
goto bail;
/* LCOV_EXCL_STOP */
}
if (task->state == TASK_STATE_ERROR_CONTINUE) {
++soft_error;
continue;
}
if (task->state == TASK_STATE_IOERROR_CONTINUE) {
++io_error;
if (io_error >= state->opt.io_error_limit) {
/* LCOV_EXCL_START */
log_fatal(EIO, "DANGER! Too many input/output errors in the %s disk. It isn't possible to continue.\n", disk->dir);
log_fatal(EIO, "Stopping at block %" PRIu64 "\n", blockcur);
goto bail;
/* LCOV_EXCL_STOP */
}
/* otherwise continue */
continue;
}
if (task->state != TASK_STATE_DONE) {
/* LCOV_EXCL_START */
log_fatal(EINTERNAL, "Internal inconsistency in task state\n");
os_abort();
/* LCOV_EXCL_STOP */
}
countsize += read_size;
}
/* until now is misc */
state_usage_misc(state);
/* read the parity */
for (l = 0; l < state->level; ++l) {
struct snapraid_task* task;
unsigned levcur;
task = io_parity_read(&io, &levcur, waiting_map, &waiting_mac);
/* until now is parity */
state_usage_parity(state, waiting_map, waiting_mac);
/* handle error conditions */
if (task->state == TASK_STATE_IOERROR) {
/* LCOV_EXCL_START */
++io_error;
goto bail;
/* LCOV_EXCL_STOP */
}
if (task->state == TASK_STATE_ERROR) {
/* LCOV_EXCL_START */
++soft_error;
goto bail;
/* LCOV_EXCL_STOP */
}
if (task->state == TASK_STATE_ERROR_CONTINUE) {
++soft_error;
continue;
}
if (task->state == TASK_STATE_IOERROR_CONTINUE) {
++io_error;
if (io_error >= state->opt.io_error_limit) {
/* LCOV_EXCL_START */
log_fatal(EIO, "DANGER! Too many input/output errors in the %s disk. It isn't possible to continue.\n", lev_name(levcur));
log_fatal(EIO, "Stopping at block %" PRIu64 "\n", blockcur);
goto bail;
/* LCOV_EXCL_STOP */
}
continue;
}
if (task->state != TASK_STATE_DONE) {
/* LCOV_EXCL_START */
log_fatal(EINTERNAL, "Internal inconsistency in task state\n");
os_abort();
/* LCOV_EXCL_STOP */
}
}
/* count the number of processed block */
++countpos;
/* progress */
if (state_progress(state, &io, blockcur, countpos, countmax, countsize)) {
/* LCOV_EXCL_START */
break;
/* LCOV_EXCL_STOP */
}
/* thermal control */
if (state_thermal_alarm(state)) {
/* until now is misc */
state_usage_misc(state);
state_progress_stop(state);
/* complete all read-ahead without consuming the results */
io_quiesce(&io);
state_thermal_cooldown(state);
state_progress_restart(state);
/* drop until now */
state_usage_waste(state);
if (os_signal_interrupt())
break;
}
}
end:
state_progress_end(state, countpos, countmax, countsize, "Nothing to dry.\n");
state_usage_print(state);
bail:
/* stop all the worker threads */
io_stop(&io);
for (j = 0; j < diskmax; ++j) {
struct snapraid_file* file = handle[j].file;
struct snapraid_disk* disk = handle[j].disk;
ret = handle_close(&handle[j]);
if (ret == -1) {
/* LCOV_EXCL_START */
/*
* If handle_close fails, the handle was open (f != -1), which
* guarantees that both file and disk pointers are valid.
*/
log_tag("%s::%s:%s: Close error. %s.\n", es(errno), disk->name, esc_tag(file->sub), strerror(errno));
log_fatal_errno(errno, disk->name);
if (is_hw(errno)) {
++io_error;
} else {
++soft_error;
}
/* continue, as we are already exiting */
/* LCOV_EXCL_STOP */
}
}
if (soft_error || io_error) {
msg_status("\n");
msg_status("%8u soft errors\n", soft_error);
msg_status("%8u io errors\n", io_error);
}
if (soft_error)
log_fatal(ESOFT, "DANGER! Unexpected errors!\n");
if (io_error)
log_fatal(EIO, "DANGER! Unexpected input/output errors!\n");
log_tag("summary:error_soft:%u\n", soft_error);
log_tag("summary:error_io:%u\n", io_error);
if (soft_error + io_error == 0)
log_tag("summary:exit:ok\n");
else
log_tag("summary:exit:error\n");
log_flush();
free(handle);
free(waiting_map);
io_done(&io);
if (soft_error + io_error != 0)
return -1;
if (alert < 0)
return -1;
return 0;
}
int state_dry(struct snapraid_state* state, block_off_t blockstart, block_off_t blockcount)
{
block_off_t blockmax;
int ret;
struct snapraid_parity_handle parity_handle[LEV_MAX];
unsigned process_error;
unsigned l;
msg_progress("Drying...\n");
blockmax = parity_allocated_size(state);
if (blockstart > blockmax) {
/* LCOV_EXCL_START */
log_fatal(EUSER, "Error in the specified starting block %" PRIu64 ". It's larger than the parity size %" PRIu64 ".\n", blockstart, blockmax);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
/* adjust the number of block to process */
if (blockcount != 0 && blockcount < blockmax - blockstart) {
blockmax = blockstart + blockcount;
}
/*
* Open the file for reading
* it may fail if the file doesn't exist, in this case we continue to dry the files
*/
for (l = 0; l < state->level; ++l) {
ret = parity_open(&parity_handle[l], &state->parity[l], l, state->file_mode, state->block_size, state->opt.parity_limit_size);
if (ret == -1) {
/* LCOV_EXCL_START */
log_tag("parity_%s:%u:%s: Open error. %s.\n", es(errno), 0, lev_config_name(l), strerror(errno));
log_fatal_errno(errno, lev_config_name(l));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
process_error = 0;
/* skip degenerated cases of empty parity, or skipping all */
if (blockstart < blockmax) {
ret = state_dry_process(state, parity_handle, blockstart, blockmax);
if (ret == -1) {
/* LCOV_EXCL_START */
++process_error;
/* continue, as we are already exiting */
/* LCOV_EXCL_STOP */
}
}
/* try to close only if opened */
for (l = 0; l < state->level; ++l) {
ret = parity_close(&parity_handle[l]);
if (ret == -1) {
/* LCOV_EXCL_START */
log_tag("parity_%s::%s: Close error. %s.\n", es(errno), lev_config_name(l), strerror(errno));
log_fatal_errno(errno, lev_config_name(l));
++process_error;
/* continue, as we are already exiting */
/* LCOV_EXCL_STOP */
}
}
if (process_error != 0)
return -1;
if (log_hardware_errors() != 0) {
msg_status("Everything done, but hardware errors were encountered in the process\n");
return -1;
}
msg_status("Everything OK\n");
return 0;
}

View file

@ -1,165 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
#include "os/portable.h"
#include "support.h"
#include "util.h"
#include "elem.h"
#include "state.h"
#include "parity.h"
#include "handle.h"
/****************************************************************************/
/* dup */
struct snapraid_hash {
struct snapraid_disk* disk; /**< Disk. */
struct snapraid_file* file; /**< File. */
unsigned char hash[HASH_MAX]; /**< Hash of the whole file. */
/* nodes for data structures */
tommy_hashdyn_node node;
};
static void hash_size_store(unsigned char* ptr, uint64_t size)
{
ptr[0] = (unsigned char)(size >> 0);
ptr[1] = (unsigned char)(size >> 8);
ptr[2] = (unsigned char)(size >> 16);
ptr[3] = (unsigned char)(size >> 24);
ptr[4] = (unsigned char)(size >> 32);
ptr[5] = (unsigned char)(size >> 40);
ptr[6] = (unsigned char)(size >> 48);
ptr[7] = (unsigned char)(size >> 56);
}
struct snapraid_hash* hash_alloc(struct snapraid_state* state, struct snapraid_disk* disk, struct snapraid_file* file)
{
struct snapraid_hash* hash;
block_off_t i;
unsigned char* buf;
size_t hash_size = BLOCK_HASH_SIZE;
size_t data_size = file->blockmax * hash_size;
hash = malloc_nofail(sizeof(struct snapraid_hash));
hash->disk = disk;
hash->file = file;
buf = malloc_nofail(data_size + sizeof(uint64_t));
/* set the back pointer */
for (i = 0; i < file->blockmax; ++i) {
struct snapraid_block* block = fs_file2block_get(file, i);
hash_copy(buf + i * hash_size, block->hash);
if (!block_has_updated_hash(block)) {
free(buf);
free(hash);
return 0;
}
}
hash_size_store(buf + data_size, (uint64_t)file->size);
memhash(state->besthash, state->hashseed, hash->hash, buf, data_size + sizeof(uint64_t));
free(buf);
return hash;
}
static inline tommy_hash_t hash_hash(struct snapraid_hash* hash)
{
#if TOMMY_SIZE_BIT == 64
return tommy_hash_u64(0, hash->hash, HASH_MAX);
#else
return tommy_hash_u32(0, hash->hash, HASH_MAX);
#endif
}
static void hash_free(void* void_hash)
{
struct snapraid_hash* hash = void_hash;
free(hash);
}
int hash_compare(const void* void_arg, const void* void_data)
{
const char* arg = void_arg;
const struct snapraid_hash* hash = void_data;
return memcmp(arg, hash->hash, HASH_MAX);
}
void state_dup(struct snapraid_state* state)
{
tommy_hashdyn hashset;
tommy_node* i;
unsigned count;
data_off_t size;
tommy_hashdyn_init(&hashset);
count = 0;
size = 0;
msg_progress("Comparing...\n");
/* for each disk */
for (i = state->disklist; i != 0; i = i->next) {
tommy_node* j;
struct snapraid_disk* disk = i->data;
/* for each file */
for (j = disk->filelist; j != 0; j = j->next) {
struct snapraid_file* file = j->data;
struct snapraid_hash* hash;
tommy_hash_t hash_val;
/* if empty, skip it */
if (file->size == 0)
continue;
hash = hash_alloc(state, disk, file);
/* if no hash, skip it */
if (!hash)
continue;
hash_val = hash_hash(hash);
struct snapraid_hash* found = tommy_hashdyn_search(&hashset, hash_compare, hash->hash, hash_val);
if (found) {
++count;
size += found->file->size;
log_tag("dup:%s:%s:%s:%s:%" PRIu64 ": dup\n", disk->name, esc_tag(file->sub), found->disk->name, esc_tag(found->file->sub), found->file->size);
printf("%12" PRIu64 " %s = %s\n", file->size, fmt_term(disk, file->sub), fmt_term(found->disk, found->file->sub));
hash_free(hash);
} else {
tommy_hashdyn_insert(&hashset, &hash->node, hash, hash_val);
}
}
}
tommy_hashdyn_foreach(&hashset, hash_free);
tommy_hashdyn_done(&hashset);
msg_status("\n");
msg_status("%8u duplicates, for %" PRIu64 " GB\n", count, size / GIGA);
if (count)
msg_status("There are duplicates!\n");
else
msg_status("No duplicates\n");
log_tag("summary:dup_count:%u\n", count);
log_tag("summary:dup_size:%" PRIu64 "\n", size);
if (count == 0) {
log_tag("summary:exit:unique\n");
} else {
log_tag("summary:exit:dup\n");
}
log_flush();
}

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,612 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
#include "os/portable.h"
#include "elem.h"
#include "support.h"
#include "handle.h"
/****************************************************************************/
/* handle */
int handle_open_create(struct snapraid_handle* handle, struct snapraid_file* file, int mode, int create)
{
int ret;
int flags;
char path[PATH_MAX];
char path_unrecoverable[PATH_MAX];
/* if it's the same file, and already opened, nothing to do */
if (handle->file == file && handle->f != -1) {
return 0;
}
advise_init(&handle->advise, mode);
pathprint(path, sizeof(path), "%s%s", handle->disk->dir, file->sub);
pathprint(path_unrecoverable, sizeof(path_unrecoverable), "%s.unrecoverable", path);
/* initial values, changed later if required */
handle->created = 0;
handle->readonly_errno = 0;
/*
* Flags for opening
* O_BINARY: open as binary file (Windows only)
* O_NOFOLLOW: do not follow links to ensure to open the real file
*/
flags = O_BINARY | O_NOFOLLOW | advise_flags(&handle->advise);
/*
* If this recovery attempt was actually quarantined during the current fix run,
* continue operating on its .unrecoverable copy.
*
* FILE_IS_QUARANTINED is runtime state and is not carried to a later fix.
* FILE_IS_DAMAGED alone does not imply that the file was physically quarantined,
* because some fix modes deliberately keep damaged files under their normal name.
*/
if (file_flag_has(file, FILE_IS_QUARANTINED)) {
handle->f = open(path_unrecoverable, flags | O_RDWR);
/* if failed for missing write permission */
if (handle->f == -1 && (errno == EACCES || errno == EROFS)) {
int saved_errno = errno;
/* open for read-only */
handle->f = open(path_unrecoverable, flags | O_RDONLY);
if (handle->f != -1) {
handle->readonly_errno = saved_errno;
}
}
pathcpy(handle->path, sizeof(handle->path), path_unrecoverable);
} else {
/*
* Start every recovery attempt from the normal filename.
*
* Do not reuse an .unrecoverable file left by a previous fix. It may
* contain recovered CHG blocks whose CURRENT generation could not be
* proven. That ambiguity is runtime state and is not persisted with
* the file. Reopening such a file in a later fix would make those CHG
* blocks appear merely readable and could incorrectly treat them as
* valid CURRENT data.
*
* A previous .unrecoverable file is therefore kept only as the
* best-effort result of that recovery attempt, not as input for a
* subsequent one.
*/
handle->f = open(path, flags | O_RDWR);
/* if failed for missing write permission */
if (handle->f == -1 && (errno == EACCES || errno == EROFS)) {
int saved_errno = errno;
/* open for read-only */
handle->f = open(path, flags | O_RDONLY);
if (handle->f != -1) {
handle->readonly_errno = saved_errno;
}
}
/* if failed for missing file and creation allowed */
if (handle->f == -1 && errno == ENOENT && create) {
ret = mkancestor(path);
if (ret != 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
handle->f = open(path, flags | O_RDWR | O_CREAT | O_EXCL, 0600);
if (handle->f != -1) {
handle->created = 1;
} else if (errno == EEXIST) {
/* if created concurrently, reopen safely */
handle->f = open(path, flags | O_RDWR);
}
}
pathcpy(handle->path, sizeof(handle->path), path);
}
if (handle->f == -1) {
/*
* If creation was not requested, a missing file is an expected condition,
* not a fatal error.
*/
if (create || (errno != ENOENT && errno != ENOTDIR)) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error opening file '%s'. %s.\n", handle->path, strerror(errno));
/* LCOV_EXCL_STOP */
}
int saved_errno = errno;
handle_close(handle);
errno = saved_errno;
return -1;
}
/* just opened */
handle->file = file;
/* get the stat info */
ret = fstat(handle->f, &handle->st);
if (ret != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error accessing file '%s'. %s.\n", handle->path, strerror(errno));
handle_close(handle);
return -1;
/* LCOV_EXCL_STOP */
}
if (!S_ISREG(handle->st.st_mode)) {
/* LCOV_EXCL_START */
errno = ESOFT;
log_fatal(errno, "Error accessing file '%s' for not regular file.\n", handle->path);
handle_close(handle);
return -1;
/* LCOV_EXCL_STOP */
}
ret = advise_open(&handle->advise, handle->f);
if (ret != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error advising file '%s'. %s.\n", handle->path, strerror(errno));
handle_close(handle);
return -1;
/* LCOV_EXCL_STOP */
}
return 0;
}
/**
* Move an opened file to its persistent .unrecoverable name.
*/
int handle_quarantine(struct snapraid_handle* handle, struct snapraid_file* file, int mode)
{
char path[PATH_MAX];
char path_to[PATH_MAX];
int ret;
(void)mode;
/* already quarantined during the current fix run */
if (file_flag_has(file, FILE_IS_QUARANTINED))
return 0;
/* mark this recovery attempt as damaged */
file_flag_set(file, FILE_IS_DAMAGED);
pathprint(path, sizeof(path), "%s%s", handle->disk->dir, file->sub);
pathprint(path_to, sizeof(path_to), "%s%s.unrecoverable", handle->disk->dir, file->sub);
#ifdef _WIN32
/*
* Windows may not allow renaming an opened file. Close it before
* replacing the previous quarantine and renaming the current file.
*/
ret = handle_close(handle);
if (ret != 0)
return -1;
ret = rename(path, path_to);
if (ret != 0) {
/* LCOV_EXCL_START */
log_error(errno, "Error renaming file '%s' to '%s'. %s.\n", path, path_to, strerror(errno));
return -1;
/* LCOV_EXCL_STOP */
}
file_flag_set(file, FILE_IS_QUARANTINED);
/*
* FILE_IS_QUARANTINED is set, so handle_open_create() reopens the
* .unrecoverable file belonging to the current recovery attempt.
*/
ret = handle_open_create(handle, file, mode, 0);
if (ret != 0)
return -1;
#else
/*
* POSIX rename() atomically replaces an existing destination file.
* The opened descriptor continues to reference the renamed inode, so
* no close/reopen is required.
*/
ret = rename(path, path_to);
if (ret != 0) {
/* LCOV_EXCL_START */
log_error(errno, "Error renaming file '%s' to '%s'. %s.\n", path, path_to, strerror(errno));
return -1;
/* LCOV_EXCL_STOP */
}
file_flag_set(file, FILE_IS_QUARANTINED);
pathcpy(handle->path, sizeof(handle->path), path_to);
#endif
return 0;
}
/**
* Remove an .unrecoverable file left by a previous recovery attempt.
*/
int handle_unrecoverable_remove(struct snapraid_handle* handle, struct snapraid_file* file)
{
char path[PATH_MAX];
int ret;
pathprint(path, sizeof(path), "%s%s.unrecoverable", handle->disk->dir, file->sub);
ret = remove(path);
if (ret != 0 && errno != ENOENT) {
/* LCOV_EXCL_START */
log_error(errno, "Error removing file '%s'. %s.\n", path, strerror(errno));
return -1;
/* LCOV_EXCL_STOP */
}
return 0;
}
int handle_truncate(struct snapraid_handle* handle, struct snapraid_file* file)
{
int ret;
if (handle->readonly_errno != 0) {
if (file->size == handle->st.st_size)
return 0;
/* LCOV_EXCL_START */
errno = handle->readonly_errno;
log_fatal(errno, "Failed to truncate file '%s' for missing write permission. %s.\n", handle->path, strerror(errno));
return -1;
/* LCOV_EXCL_STOP */
}
ret = ftruncate(handle->f, file->size);
if (ret != 0) {
/* LCOV_EXCL_START */
if (errno == EACCES) {
log_fatal(errno, "Failed to truncate file '%s' for missing write permission.\n", handle->path);
} else {
log_fatal(errno, "Error truncating file '%s'. %s.\n", handle->path, strerror(errno));
}
return -1;
/* LCOV_EXCL_STOP */
}
/* keep the cached EOF current; the other stat fields remain the open snapshot */
handle->st.st_size = file->size;
return 0;
}
int handle_open(struct snapraid_handle* handle, struct snapraid_file* file, int mode, log_ptr* out_missing)
{
int ret;
int flags;
if (!out_missing)
out_missing = log_error;
/* if already opened, nothing to do */
if (handle->file != 0 && handle->file == file && handle->f != -1) {
return 0;
}
advise_init(&handle->advise, mode);
pathprint(handle->path, sizeof(handle->path), "%s%s", handle->disk->dir, file->sub);
/* for sure not created */
handle->created = 0;
handle->readonly_errno = 0;
/*
* Flags for opening
* O_BINARY: open as binary file (Windows only)
* O_NOFOLLOW: do not follow links to ensure to open the real file
*/
flags = O_BINARY | O_NOFOLLOW | advise_flags(&handle->advise);
/* open for read */
handle->f = open_noatime(handle->path, flags | O_RDONLY);
if (handle->f == -1) {
if (errno == ENOENT)
out_missing(errno, "Missing file '%s'.\n", handle->path);
else if (errno == EACCES)
log_error(errno, "Permission denied for file '%s'.\n", handle->path);
else
log_error(errno, "Error opening file '%s'. %s.\n", handle->path, strerror(errno));
handle_close(handle);
return -1;
}
/* just opened */
handle->file = file;
/* get the stat info */
ret = fstat(handle->f, &handle->st);
if (ret != 0) {
/* LCOV_EXCL_START */
log_error(errno, "Error accessing file '%s'. %s.\n", handle->path, strerror(errno));
handle_close(handle);
return -1;
/* LCOV_EXCL_STOP */
}
if (!S_ISREG(handle->st.st_mode)) {
/* LCOV_EXCL_START */
errno = ESOFT;
log_error(errno, "Error accessing file '%s' for not regular file.\n", handle->path);
handle_close(handle);
return -1;
/* LCOV_EXCL_STOP */
}
ret = advise_open(&handle->advise, handle->f);
if (ret != 0) {
/* LCOV_EXCL_START */
log_error(errno, "Error advising file '%s'. %s.\n", handle->path, strerror(errno));
handle_close(handle);
return -1;
/* LCOV_EXCL_STOP */
}
return 0;
}
int handle_close(struct snapraid_handle* handle)
{
int f_ret = 0;
int f_errno = 0;
/* close if open */
if (handle->f != -1) {
int ret = advise_close(&handle->advise, handle->f);
if (ret != 0) {
/* LCOV_EXCL_START */
f_ret = -1;
f_errno = errno;
log_fatal(errno, "Error advising file '%s'. %s.\n", handle->path, strerror(errno));
/* LCOV_EXCL_STOP */
}
ret = close(handle->f);
if (ret != 0) {
/* LCOV_EXCL_START */
if (f_ret == 0) {
f_ret = -1;
f_errno = errno;
}
log_fatal(errno, "Error closing file '%s'. %s.\n", handle->path, strerror(errno));
/* LCOV_EXCL_STOP */
}
}
/* reset the descriptor */
handle->file = 0;
handle->f = -1;
handle->readonly_errno = 0;
if (f_ret != 0)
errno = f_errno;
return f_ret;
}
ssize_t handle_read(struct snapraid_handle* handle, block_off_t file_pos, unsigned char* block_buffer, unsigned block_size, log_ptr* out_missing)
{
ssize_t read_ret;
data_off_t offset;
size_t read_size;
unsigned count;
int ret;
offset = file_pos * block_size;
if (!out_missing)
out_missing = log_error;
/* check if we are going to read only not initialized data */
if (offset >= handle->st.st_size) {
/* if the file is missing, it's at 0 size, or it's rebuilt while reading */
if (offset == handle->st.st_size || handle->st.st_size == 0) {
errno = ENOENT;
if (offset == 0) {
out_missing(errno, "Missing file '%s'.\n", handle->path);
} else {
out_missing(errno, "Missing data in file '%s' at offset %" PRIu64 ".\n", handle->path, offset);
}
} else {
errno = ENXIO;
log_error(errno, "Reading over the end from file '%s' at offset %" PRIu64 ".\n", handle->path, offset);
}
return -1;
}
read_size = file_block_size(handle->file, file_pos, block_size);
bw_limit(handle->bw, block_size);
count = 0;
do {
read_ret = pread(handle->f, block_buffer + count, block_size - count, offset + count);
if (read_ret == -1) {
if (errno == EINTR)
continue;
/* LCOV_EXCL_START */
log_error(errno, "Error reading file '%s' at offset %" PRIu64 " for size %u. %s.\n", handle->path, offset + count, block_size - count, strerror(errno));
return -1;
/* LCOV_EXCL_STOP */
}
if (read_ret == 0) {
/* LCOV_EXCL_START */
errno = ENXIO;
log_error(errno, "Unexpected end of file '%s' at offset %" PRIu64 ". %s.\n", handle->path, offset, strerror(errno));
return -1;
/* LCOV_EXCL_STOP */
}
count += read_ret;
} while (count < read_size);
/* pad with 0 */
if (read_size < block_size) {
memset(block_buffer + read_size, 0, block_size - read_size);
}
ret = advise_read(&handle->advise, handle->f, offset, block_size);
if (ret != 0) {
/* LCOV_EXCL_START */
log_error(errno, "Error advising file '%s'. %s.\n", handle->path, strerror(errno));
return -1;
/* LCOV_EXCL_STOP */
}
return read_size;
}
int handle_write(struct snapraid_handle* handle, block_off_t file_pos, unsigned char* block_buffer, unsigned block_size)
{
ssize_t write_ret;
data_off_t offset;
ssize_t write_size;
ssize_t count;
int ret;
if (handle->readonly_errno != 0) {
/* LCOV_EXCL_START */
errno = handle->readonly_errno;
log_fatal(errno, "Failed to write file '%s' for missing write permission. %s.\n", handle->path, strerror(errno));
return -1;
/* LCOV_EXCL_STOP */
}
offset = file_pos * block_size;
write_size = file_block_size(handle->file, file_pos, block_size);
bw_limit(handle->bw, write_size);
count = 0;
do {
write_ret = pwrite(handle->f, block_buffer + count, write_size - count, offset + count);
if (write_ret == -1) {
if (errno == EINTR)
continue;
/* LCOV_EXCL_START */
log_fatal(errno, "Error writing file '%s'. %s.\n", handle->path, strerror(errno));
return -1;
/* LCOV_EXCL_STOP */
}
if (write_ret == 0) {
/* LCOV_EXCL_START */
errno = ENXIO;
log_fatal(errno, "Unexpected 0 write to file '%s'. %s.\n", handle->path, strerror(errno));
return -1;
/* LCOV_EXCL_STOP */
}
count += write_ret;
} while (count < write_size);
/* keep the cached EOF current; the other stat fields remain the open snapshot */
if (handle->st.st_size < offset + write_size)
handle->st.st_size = offset + write_size;
ret = advise_write(&handle->advise, handle->f, offset, block_size);
if (ret != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error advising file '%s'. %s.\n", handle->path, strerror(errno));
return -1;
/* LCOV_EXCL_STOP */
}
return 0;
}
int handle_utime(struct snapraid_handle* handle)
{
int ret;
/* do nothing if not opened */
if (handle->f == -1)
return 0;
ret = fmtime(handle->f, handle->file->mtime_sec, handle->file->mtime_nsec);
if (ret != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error timing file '%s'. %s.\n", handle->file->sub, strerror(errno));
return -1;
/* LCOV_EXCL_STOP */
}
return 0;
}
struct snapraid_handle* handle_mapping(struct snapraid_state* state, unsigned* handlemax)
{
tommy_node* i;
unsigned j;
unsigned size = 0;
struct snapraid_handle* handle;
/*
* The handle array is indexed by persistent parity mapping position,
* not by data disk count or enumeration order.
*
* Mapping holes must remain as empty handles: they contribute zero data
* to RAID while preserving the parity column of following disks.
*
* Do not compact this array: renumbering a disk changes its RAID column
* and invalidates existing parity against the content file mapping.
*/
/* get the size of the mapping */
size = 0;
for (i = state->maplist; i != 0; i = i->next) {
struct snapraid_map* map = i->data;
if (map->position > size)
size = map->position;
}
++size; /* size is one more than the max */
handle = nalloc_nofail(size, sizeof(struct snapraid_handle));
for (j = 0; j < size; ++j) {
/* default for empty position */
handle[j].disk = 0;
handle[j].file = 0;
handle[j].f = -1;
handle[j].readonly_errno = 0;
handle[j].bw = 0;
}
/* set the vector */
for (i = state->disklist; i != 0; i = i->next) {
struct snapraid_map* map;
struct snapraid_disk* disk = i->data;
tommy_node* k;
/* search the mapping for this disk */
map = 0;
for (k = state->maplist; k != 0; k = k->next) {
map = k->data;
if (pathcmp(disk->name, map->name) == 0)
break;
}
if (!map) {
/* LCOV_EXCL_START */
log_fatal(EINTERNAL, "Internal error for inconsistent disk mapping.\n");
os_abort();
/* LCOV_EXCL_STOP */
}
handle[map->position].disk = disk;
}
*handlemax = size;
return handle;
}

View file

@ -1,93 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
#ifndef HANDLE_H
#define HANDLE_H
#include "state.h"
#include "support.h"
#include "bw.h"
/****************************************************************************/
/* handle */
struct snapraid_handle {
char path[PATH_MAX]; /**< Path of the file. */
struct snapraid_disk* disk; /**< Disk of the file. */
struct snapraid_file* file; /**< File opened. When the file is closed, it's set to 0. */
int f; /**< Handle of the file. */
struct stat st; /**< Stat info of the opened file. st_size tracks the current EOF after recovery writes. */
struct advise_struct advise; /**< Advise information. */
int created; /**< If the file was created, otherwise it was already existing. */
int readonly_errno; /**< Non-zero if opened read-only as fallback. */
struct snapraid_bw* bw; /**< Context for bandwidth limiting. */
};
/**
* Open or create a recovery file.
* A new recovery attempt always uses the normal filename, even if a previous .unrecoverable file exists.
* FILE_IS_QUARANTINED determines whether the .unrecoverable filename is opened in the current run.
* If create is non-zero, a missing file is created and handle->created is set.
* If create is zero, a missing file is not created, returning -1 with errno == ENOENT.
* The initial size of the file is stored in the file->st struct.
* If the file cannot be opened for write access, it's opened with read-only access.
* The read-only access works only if the file has already the correct size and doesn't need to be modified.
*/
int handle_open_create(struct snapraid_handle* handle, struct snapraid_file* file, int mode, int create);
/**
* Move an opened file to its persistent .unrecoverable name.
* A previous .unrecoverable from an older recovery attempt is replaced.
* If already quarantined in the current run, do nothing.
* On error, log the failure and return -1 with errno set.
*/
int handle_quarantine(struct snapraid_handle* handle, struct snapraid_file* file, int mode);
/**
* Remove an .unrecoverable file left by a previous recovery attempt.
* A missing .unrecoverable file is not an error.
* On error, log the failure and return -1 with errno set.
*/
int handle_unrecoverable_remove(struct snapraid_handle* handle, struct snapraid_file* file);
/**
* Truncate a file if required.
*/
int handle_truncate(struct snapraid_handle* handle, struct snapraid_file* file);
/**
* Open a file.
* The file is opened for reading.
*/
int handle_open(struct snapraid_handle* handle, struct snapraid_file* file, int mode, log_ptr* out_missing);
/**
* Close a file.
*/
int handle_close(struct snapraid_handle* handle);
/**
* Read a block from a file.
* If the read block is shorter, it's padded with 0.
*/
ssize_t handle_read(struct snapraid_handle* handle, block_off_t file_pos, unsigned char* block_buffer, unsigned block_size, log_ptr* out_missing);
/**
* Write a block to a file.
*/
int handle_write(struct snapraid_handle* handle, block_off_t file_pos, unsigned char* block_buffer, unsigned block_size);
/**
* Change the modification time of the file to the saved value.
*/
int handle_utime(struct snapraid_handle* handle);
/**
* Map the unsorted list of disk to an ordered vector.
* \param diskmax The size of the vector.
* \return The allocated vector of pointers.
*/
struct snapraid_handle* handle_mapping(struct snapraid_state* state, unsigned* diskmax);
#endif

View file

@ -1,567 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2013 Andrea Mazzoleni
#include "os/portable.h"
#include "support.h"
#include "import.h"
/****************************************************************************/
/* import */
/**
* Compare the hash of two import blocks.
*/
int import_block_hash_compare(const void* void_arg, const void* void_data)
{
const unsigned char* arg = void_arg;
const struct snapraid_import_block* block = void_data;
return memcmp(arg, block->hash, BLOCK_HASH_SIZE);
}
int import_block_prevhash_compare(const void* void_arg, const void* void_data)
{
const unsigned char* arg = void_arg;
const struct snapraid_import_block* block = void_data;
return memcmp(arg, block->prevhash, BLOCK_HASH_SIZE);
}
/**
* Compute the hash of the hash for an import block.
* We just use the first 32 bit of the hash itself.
*/
static inline tommy_uint32_t import_block_hash(const unsigned char* hash)
{
/* the hash data is not aligned, and we cannot access it with a direct cast */
return hash[0] | ((uint32_t)hash[1] << 8) | ((uint32_t)hash[2] << 16) | ((uint32_t)hash[3] << 24);
}
static void import_file(struct snapraid_state* state, const char* path, uint64_t size)
{
struct snapraid_import_file* file;
block_off_t i;
data_off_t offset;
void* buffer;
ssize_t ret;
int f;
int flags;
int advise_errno;
unsigned block_size = state->block_size;
struct advise_struct advise;
block_off_t blockmax;
blockmax = size / block_size;
if (size % block_size != 0)
++blockmax;
if (blockmax > BLOCK_MAX
#if SIZE_MAX == UINT32_MAX
|| blockmax > (block_off_t)(SIZE_MAX / sizeof(struct snapraid_import_block))
#endif
) {
#if SIZE_MAX == UINT32_MAX
log_fatal(ESOFT, "File '%s' with %" PRIu64 " blocks is too large for a 32-bit build. Use a 64-bit build or increase the block size.\n", path, blockmax);
#else
log_fatal(ESOFT, "File '%s' with %" PRIu64 " blocks is too large. Increase the block size.\n", path, blockmax);
#endif
exit(EXIT_FAILURE);
}
file = malloc_nofail(sizeof(struct snapraid_import_file));
file->path = strdup_nofail(path);
file->size = size;
file->blockmax = blockmax;
file->blockimp = nalloc_nofail((size_t)file->blockmax, sizeof(struct snapraid_import_block));
file->is_runtime = 1;
buffer = malloc_nofail(block_size);
advise_init(&advise, state->file_mode);
/* open for read */
flags = O_RDONLY | O_BINARY | advise_flags(&advise);
f = open(path, flags);
if (f == -1) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error opening file '%s'. %s.\n", path, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
ret = advise_open(&advise, f);
if (ret != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error advising file '%s'. %s.\n", path, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
offset = 0;
for (i = 0; i < file->blockmax; ++i) {
struct snapraid_import_block* block = &file->blockimp[i];
size_t read_size = block_size;
size_t count;
if (read_size > size)
read_size = size;
count = 0;
do {
ret = read(f, (char*)buffer + count, read_size - count);
if (ret < 0) {
if (errno == EINTR)
continue;
/* LCOV_EXCL_START */
log_fatal(errno, "Error reading file '%s'. %s.\n", path, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (ret == 0) {
/* LCOV_EXCL_START */
errno = ENXIO;
log_fatal(errno, "Unexpected end of file '%s'. %s.\n", path, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
count += ret;
} while (count < read_size);
if (read_size < block_size)
memset((unsigned char*)buffer + read_size, 0, block_size - read_size);
block->file = file;
block->offset = offset;
block->size = read_size;
memhash_block(state->hash, state->hashseed, block->hash, buffer, read_size, block_size);
tommy_hashdyn_insert(&state->importset, &block->nodeset, block, import_block_hash(block->hash));
/* if we are in a rehash state */
if (state->prevhash != HASH_UNDEFINED) {
/* compute also the previous hash */
memhash_block(state->prevhash, state->prevhashseed, block->prevhash, buffer, read_size, block_size);
tommy_hashdyn_insert(&state->previmportset, &block->prevnodeset, block, import_block_hash(block->prevhash));
}
offset += read_size;
size -= read_size;
}
ret = advise_close(&advise, f);
advise_errno = ret != 0 ? errno : 0;
ret = close(f);
if (advise_errno != 0) {
/* LCOV_EXCL_START */
errno = advise_errno;
log_fatal(errno, "Error advising file '%s'. %s.\n", path, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (ret != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error closing file '%s'. %s.\n", path, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
tommy_list_insert_tail(&state->importlist, &file->nodelist, file);
free(buffer);
}
static void import_dealloc(struct snapraid_state* state, const char* dir, struct snapraid_dealloc* dealloc)
{
char path[PATH_MAX];
struct snapraid_import_file* file;
block_off_t i;
block_off_t blockmax;
data_off_t offset;
data_off_t size;
unsigned block_size = state->block_size;
pathcpy(path, sizeof(path), dir);
pathcat(path, sizeof(path), dealloc->sub);
size = dealloc->size;
blockmax = size / block_size;
if (size % block_size != 0)
++blockmax;
if (blockmax > BLOCK_MAX
#if SIZE_MAX == UINT32_MAX
|| blockmax > (block_off_t)(SIZE_MAX / sizeof(struct snapraid_import_block))
#endif
) {
#if SIZE_MAX == UINT32_MAX
log_fatal(ESOFT, "File '%s' with %" PRIu64 " blocks is too large for a 32-bit build. Use a 64-bit build or increase the block size.\n", path, blockmax);
#else
log_fatal(ESOFT, "File '%s' with %" PRIu64 " blocks is too large. Increase the block size.\n", path, blockmax);
#endif
exit(EXIT_FAILURE);
}
file = malloc_nofail(sizeof(struct snapraid_import_file));
file->path = strdup_nofail(path);
file->size = size;
file->blockmax = blockmax;
file->blockimp = nalloc_nofail((size_t)file->blockmax, sizeof(struct snapraid_import_block));
file->is_runtime = 0;
offset = 0;
for (i = 0; i < file->blockmax; ++i) {
struct snapraid_import_block* block = &file->blockimp[i];
ssize_t read_size = block_size;
if (read_size > size)
read_size = size;
block->file = file;
block->offset = offset;
block->size = read_size;
if (dealloc->block[i].prev) {
hash_invalid_set(block->hash);
hash_copy(block->prevhash, dealloc->block[i].hash);
/* do not insert invalid hashes */
if (!hash_is_invalid(block->prevhash))
tommy_hashdyn_insert(&state->previmportset, &block->prevnodeset, block, import_block_hash(block->prevhash));
} else {
hash_copy(block->hash, dealloc->block[i].hash);
hash_invalid_set(block->prevhash);
/* do not insert invalid hashes */
if (!hash_is_invalid(block->hash))
tommy_hashdyn_insert(&state->importset, &block->nodeset, block, import_block_hash(block->hash));
}
offset += read_size;
size -= read_size;
}
tommy_list_insert_tail(&state->importlist, &file->nodelist, file);
}
void import_file_free(void* void_file)
{
struct snapraid_import_file* file = void_file;
free(file->path);
free(file->blockimp);
free(file);
}
static int state_import_fetch_candidate(struct snapraid_state* state, int rehash, struct snapraid_import_block* block, const unsigned char* hash, unsigned char* buffer)
{
ssize_t ret;
int f;
unsigned block_size = state->block_size;
size_t read_size;
size_t count;
unsigned char buffer_hash[HASH_MAX];
const char* path;
path = block->file->path;
read_size = block->size;
if (!block->file->is_runtime) {
struct stat st;
/*
* A deallocated candidate is historical and may be stale or shorter.
* Validate metadata to ensure the file exists, is regular, and contains data at the offset.
*/
if (stat(path, &st) != 0) {
if (errno == ENOENT) {
log_error(EUSER, "WARNING! Unexpected missing deallocated file '%s'.\n", path);
} else {
log_error(errno, "WARNING! Error stating deallocated file '%s'. %s.\n", path, strerror(errno));
}
return -1;
}
if (!S_ISREG(st.st_mode)) {
log_error(EUSER, "WARNING! Unexpected non-regular deallocated file '%s'.\n", path);
return -1;
}
if ((data_off_t)st.st_size < block->offset || (data_off_t)st.st_size - block->offset < (data_off_t)read_size) {
log_error(EUSER, "WARNING! Unexpected short deallocated file '%s'.\n", path);
return -1;
}
}
f = open(path, O_RDONLY | O_BINARY);
if (f == -1) {
/*
* A deallocated source is historical and may be stale, so failure to open is a
* best-effort miss that lets the caller try another matching candidate.
* A runtime import was hashed in this run; its disappearance violates
* that invariant and must remain fatal.
*/
if (!block->file->is_runtime) {
if (errno == ENOENT) {
log_error(EUSER, "WARNING! Unexpected missing deallocated file '%s'.\n", path);
} else {
log_error(errno, "WARNING! Error opening deallocated file '%s'. %s.\n", path, strerror(errno));
}
return -1;
}
/* LCOV_EXCL_START */
if (errno == ENOENT) {
log_fatal(errno, "DANGER! file '%s' disappeared.\n", path);
log_fatal(errno, "If you moved it, please rerun the same command.\n");
} else {
log_fatal(errno, "Error opening file '%s'. %s.\n", path, strerror(errno));
}
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
count = 0;
do {
ret = pread(f, (char*)buffer + count, read_size - count, block->offset + count);
if (ret < 0) {
if (errno == EINTR)
continue;
if (!block->file->is_runtime) {
close(f);
log_error(errno, "WARNING! Error reading deallocated file '%s'. %s.\n", path, strerror(errno));
return -1;
}
/* LCOV_EXCL_START */
log_fatal(errno, "Error reading file '%s'. %s.\n", path, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (ret == 0) {
if (!block->file->is_runtime) {
close(f);
log_error(EUSER, "WARNING! Unexpected end of file in deallocated file '%s'.\n", path);
return -1;
}
/* LCOV_EXCL_START */
errno = ENXIO;
log_fatal(errno, "Unexpected end of file '%s'. %s.\n", path, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
count += ret;
} while (count < read_size);
ret = close(f);
if (ret != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error closing file '%s'. %s.\n", path, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (read_size != block_size) {
/* fill the remaining with 0 */
memset(buffer + read_size, 0, block_size - read_size);
}
/* recheck the hash */
if (rehash)
memhash_block(state->prevhash, state->prevhashseed, buffer_hash, buffer, read_size, block_size);
else
memhash_block(state->hash, state->hashseed, buffer_hash, buffer, read_size, block_size);
if (memcmp(buffer_hash, hash, BLOCK_HASH_SIZE) != 0) {
/*
* Deallocated contents may have changed since they were recorded, so a
* mismatch is best-effort and another candidate may still be valid.
* A runtime import was hashed in this run; a mismatch means concurrent
* modification and must remain fatal.
*/
if (!block->file->is_runtime) {
log_error(EUSER, "WARNING! Unexpected hash mismatch from deallocated file '%s'.\n", path);
return -1;
}
/* LCOV_EXCL_START */
log_fatal(EUSER, "Mismatch in data reading file '%s'.\n", path);
log_fatal(EUSER, "Please don't change imported files while running.\n");
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
return 0;
}
int state_import_fetch(struct snapraid_state* state, int rehash, struct snapraid_block* missing_block, unsigned char* buffer)
{
tommy_hashdyn* importset;
tommy_hashdyn_node* node;
tommy_uint32_t hash32;
const unsigned char* hash = missing_block->hash;
if (rehash)
importset = &state->previmportset;
else
importset = &state->importset;
hash32 = import_block_hash(hash);
/*
* Multiple blocks may have the same digest. tommy_hashdyn_search() would
* stop at the first one, but a deallocated source may be stale, so walk
* the bucket until an exact candidate is reread and validated.
*/
node = tommy_hashdyn_bucket(importset, hash32);
while (node) {
struct snapraid_import_block* block = node->data;
/* hash32 is only an index: reject other bucket keys, then compare the full digest */
if (node->index == hash32) {
int equal;
if (rehash)
equal = import_block_prevhash_compare(hash, block) == 0;
else
equal = import_block_hash_compare(hash, block) == 0;
if (equal) {
if (state_import_fetch_candidate(state, rehash, block, hash, buffer) == 0)
return 0;
}
}
node = node->next;
}
return -1;
}
static void import_dir(struct snapraid_state* state, const char* dir)
{
DIR* d;
d = opendir(dir);
if (!d) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error opening directory '%s'. %s.\n", dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
while (1) {
char path_next[PATH_MAX];
struct stat st;
const char* name;
struct dirent* dd;
/* clear errno to detect erroneous conditions */
errno = 0;
dd = readdir(d);
if (dd == 0 && errno != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error reading directory '%s'. %s.\n", dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (dd == 0) {
break; /* finished */
}
/* skip "." and ".." files */
name = dd->d_name;
if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
continue;
pathprint(path_next, sizeof(path_next), "%s%s", dir, name);
#if HAVE_STRUCT_DIRENT_D_STAT
/* convert dirent to lstat result */
dirent_lstat(dd, &st);
/*
* If the st_mode field is missing, takes care to fill it using normal lstat()
* at now this can happen only in Windows (with HAVE_STRUCT_DIRENT_D_STAT defined),
* because we use a directory reading method that doesn't read info about ReparsePoint.
* Note that here we cannot call here lstat_sync(), because we don't know what kind
* of file is it, and lstat_sync() doesn't always work
*/
if (st.st_mode == 0) {
if (lstat(path_next, &st) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error in stat file/directory '%s'. %s.\n", path_next, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
#else
/* get lstat info about the file */
if (lstat(path_next, &st) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error in stat file/directory '%s'. %s.\n", path_next, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
#endif
if (S_ISREG(st.st_mode)) {
import_file(state, path_next, st.st_size);
} else if (S_ISDIR(st.st_mode)) {
pathslash(path_next, sizeof(path_next));
import_dir(state, path_next);
}
}
if (closedir(d) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error closing directory '%s'. %s.\n", dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
void state_import(struct snapraid_state* state, const char* dir)
{
char path[PATH_MAX];
msg_progress("Importing...\n");
/* if the hash is not full */
if (BLOCK_HASH_SIZE != HASH_MAX) {
/* LCOV_EXCL_START */
log_fatal(EUSER, "You cannot import files when using a reduced hash.\n");
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
/* add the final slash */
pathimport(path, sizeof(path), dir);
pathslash(path, sizeof(path));
import_dir(state, path);
}
void state_dealloc(struct snapraid_state* state, const char* dir, tommy_list* dealloclist)
{
/* snapshot should be enabled */
if (!state->snapshot)
return;
/* the hash must be full */
if (BLOCK_HASH_SIZE != HASH_MAX)
return;
for (tommy_node* i = tommy_list_head(dealloclist); i != 0; i = i->next) {
struct snapraid_dealloc* dealloc = i->data;
import_dealloc(state, dir, dealloc);
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,528 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2016 Andrea Mazzoleni
#ifndef IO_H
#define IO_H
#include "state.h"
#include "support.h"
#include "handle.h"
#include "parity.h"
/**
* Number of read-ahead buffers.
*
* More buffers always result in better performance.
*
* This is the scrub performance on my machine with different buffers:
*
* 1 - 380 MB/s, CPU 26%, speed 100% [SnapRAID 9.2]
* 2 - 426 MB/s, CPU 46%, speed 112%
* 4 - 452 MB/s, CPU 54%, speed 118%
* 8 - 487 MB/s, CPU 60%, speed 128%
* 16 - 505 MB/s, CPU 63%, speed 132%
* 32 - 520 MB/s, CPU 64%, speed 136% [SnapRAID <= 12.0]
* 64 - 524 MB/s, CPU 65%, speed 137% [SnapRAID > 12.0]
* 128 - 525 MB/s, CPU 66%, speed 138%
*/
#define IO_MIN 3 /* required by writers, readers can work also with 2 */
#define IO_MAX 128
/**
* State of the task.
*/
#define TASK_STATE_IOERROR_CONTINUE -6 /**< IO error. Continuation requested. */
#define TASK_STATE_ERROR_CONTINUE -5 /**< Generic error. Continuation requested. */
#define TASK_STATE_IOERROR -4 /**< IO error. Failure requested. */
#define TASK_STATE_ERROR -3 /**< Generic error. Failure requested. */
#define TASK_STATE_IOABORT -2 /**< IO error. Abort requested. */
#define TASK_STATE_ABORT -1 /**< Generic error. Abort requested. */
#define TASK_STATE_EMPTY 0 /**< Nothing to do. */
#define TASK_STATE_READY 1 /**< Ready to start. */
#define TASK_STATE_DONE 2 /**< Task completed. */
/**
* Task of work.
*
* This represents the minimal element of work that worker threads are
* going to be asked to do.
*
* It consists in reading a block of data from a disk.
*
* Note that the disk to use is defined implicitly in the worker thread.
*/
struct snapraid_task {
int state; /**< State of the task. One of the TASK_STATE_*. */
char path[PATH_MAX]; /**< Path of the file. */
struct snapraid_disk* disk; /**< Disk of the file. */
unsigned char* buffer; /**< Where to read the data. */
block_off_t position; /**< Parity position to read. */
/**
* Result of the task.
*/
struct snapraid_block* block;
struct snapraid_file* file;
block_off_t file_pos;
ssize_t read_size; /**< Size of the data read. */
int is_timestamp_different; /**< Report if file has a changed timestamp. */
int unrelated_error; /**< Error unrelated to the current parity position. */
};
/**
* Worker for tasks.
*
* This represents a worker thread designated to read/write data for a specific disk.
*/
struct snapraid_worker {
#if HAVE_THREAD
thread_id_t thread; /**< Thread context for the worker. */
int busy; /**< A read or write task is currently being processed. */
#endif
/**
* Parent pointer.
*
* Note that worker threads must NOT use this pointer to access
* the global state (io->state).
*/
struct snapraid_io* io;
void (*func)(struct snapraid_worker*, struct snapraid_task*);
/**
* Handle to data or parity.
*
* Only one of the two is valid, the other is 0.
*/
struct snapraid_handle* handle; /**< Handle at the file on the disk. */
struct snapraid_parity_handle* parity_handle; /**< Handle at the parity on the disk. */
/**
* Vector of tasks.
*
* It's a ring of tasks reused cycle after cycle.
*/
struct snapraid_task task_map[IO_MAX];
/**
* The task in progress by the worker thread.
*
* It's an index inside the ::task_map vector.
*/
unsigned index;
/**
* Which buffer base index should be used for destination.
*/
unsigned buffer_skew;
};
/**
* Number of error kind for writers.
*/
#define IO_WRITER_ERROR_BASE TASK_STATE_IOERROR_CONTINUE
#define IO_WRITER_ERROR_MAX (-IO_WRITER_ERROR_BASE)
/**
* IO system that handles all parallel reads and writes.
*
* This represents the pool of worker threads dedicated to read and write
* data from the disks.
*
* Typical scenario is:
*
* # Initialize the process
* io_start(&io, blockstart, blockmax, block_enabled);
*
* for_each_block {
* # Now read starts
* # Get the current block to process and the vector of data buffers to use
* # buffer[0..diskmax-1] are data disks
* # buffer[diskmax..diskmax+levelmax-1] are parity disks
* #
* # INTERNAL: Broadcast a read_sched signal, to signal worker threads
* # that the previous "blockcur" position is now available and the
* # buffers can be used to read a new look-ahead position.
* unsigned blockcur = io_read_next(&io, &buffer);
*
* for_each_disk {
* # Read a disk into buffer[diskcur]
* # diskcur is the disk processed, and it may come in random order
* # depending on which disk is faster
* #
* # INTERNAL: It may wait for the read_done condition in case
* # the read is not yet done.
* # The reader thread will set the condition when ready.
* struct snapraid_task* task = io_data_read(&io, &diskcur, waiting_map, &waiting_mac);
*
* # compute the hash
* ...
* }
*
* # compute the parity
* ...
*
* # Now write starts
* # At this point the parity data should ALREADY be in the buffer[diskmax+levcur]
* # Note that the only reason that the process is separated for each parity
* # is to allow to identify which is the latest and slowest disk
* io_write_preset(&io, blockcur, !parity_going_to_be_updated);
*
* for_each_parity {
* unsigned levcur;
*
* # Write a parity from buffer[diskmax+levcur]
* # levcur is the disk processed, and it may come in random order
* # depending on which disk is faster
* #
* # INTERNAL: It may wait for the write_done condition in case
* # there isn't a free position in the parity write queue.
* # The writer thread will set the condition when ready.
* io_parity_write(&io, &levcur, waiting_map, &waiting_mac);
* }
*
* # End of the write
* # INTERNAL: Broadcast a write_sched signal, to signal worker threads
* # that a new position is ready to be written
* io_write_next(&io, blockcur, !parity_going_to_be_updated, writer_error);
* }
*
* # Stop all thread after writing all queued data
* io_stop(&io);
*/
struct snapraid_io {
/**
* Pointer to the global state.
*
* Note that this pointer must NOT be accessed inside worker threads
* (e.g. data_reader/writer, parity_reader/writer functions).
* Workers must only operate on their pre-allocated buffers and local task variables,
* while any state modifications must strictly happen on the main thread
* after I/O completion.
*/
struct snapraid_state* state;
/**
* Number of read-ahead and write-cached buffers to use.
*
* Between IO_MIN and IO_MAX for thread use.
*
* If equal to 1, it means to work without any thread.
*/
unsigned io_max;
#if HAVE_THREAD
/**
* Mutex used to protect the synchronization
* between the io and the workers.
*/
thread_mutex_t io_mutex;
/**
* Condition for a new read is completed.
*
* The workers signal this condition when a new read is completed.
* The IO waits on this condition when it's waiting for
* a new read to be completed.
*/
thread_cond_t read_done;
/**
* Condition for a new read scheduled.
*
* The workers wait on this condition when they are waiting for a new
* read to process.
* The IO signals this condition when new reads are scheduled.
*/
thread_cond_t read_sched;
/**
* Condition for a new write is completed.
*
* The workers signal this condition when a new write is completed.
* The IO waits on this condition when it's waiting for
* a new write to be completed.
*/
thread_cond_t write_done;
/**
* Condition for a new write scheduled.
*
* The workers wait on this condition when they are waiting for a new
* write to process.
* The IO signals this condition when new writes are scheduled.
*/
thread_cond_t write_sched;
#endif
/**
* Base position for workers.
*
* It's the index in the ::worker_map[].
*/
unsigned data_base;
unsigned data_count;
unsigned parity_base;
unsigned parity_count;
/**
* Callbacks for workers.
*/
void (*data_reader)(struct snapraid_worker*, struct snapraid_task*);
void (*parity_reader)(struct snapraid_worker*, struct snapraid_task*);
void (*parity_writer)(struct snapraid_worker*, struct snapraid_task*);
/**
* Blocks mapping.
*
* This info is used to obtain the sequence of block
* positions to process.
*/
block_off_t block_start;
block_off_t block_max;
block_off_t block_next;
bit_vect_t* block_enabled;
/**
* Buffers for data.
*
* A pool of buffers used to store the data read.
*/
unsigned buffer_max; /**< Number of buffers. */
void* buffer_alloc_map[IO_MAX]; /**< Allocation map for buffers. */
void** buffer_map[IO_MAX]; /**< Buffers for data. */
/**
* Workers.
*
* A vector of readers, each one representing a different thread.
*/
unsigned reader_max; /**< Number of workers. */
struct snapraid_worker* reader_map; /**< Vector of workers. */
unsigned writer_max; /**< Number of workers. */
struct snapraid_worker* writer_map; /**< Vector of workers. */
/**
* List of not yet processed workers.
*
* The list has ::reader_max + 1 elements. Each element contains
* the number of the reader to process.
*
* At initialization the list is filled with [0..reader_max].
* To get the next element to process we use i = list[i + 1].
* The end is when i == reader_max.
*/
unsigned* reader_list;
unsigned* writer_list;
/**
* Exit condition for all threads.
*/
int done;
/**
* If worker threads have been started.
*/
int started;
/**
* The worker task index currently used by the operation in
* progress. It's the position in all the reader task_map[].
*
* Until the operation is in progress, the data buffer cannot be
* discarded, because it's in use.
*
* It's a rolling counter, when reaching ::io_max
* it goes again to 0.
*
* When the caller finish with this index, it calls read_sched(),
* and this ::reader_index is incremented, meaning that the data of
* the just finished index is not needed anymore and the buffer is
* available to be used for the following read-ahead.
*
* When this happens a read_sched signal is broadcasted, and all the
* workers can proceed using this now available index to have one more
* read-ahead buffer to load.
*
* In monothread mode it isn't the task index,
* but the worker index.
*/
unsigned reader_index;
/**
* The worker task index currently used by the operation in
* progress. It's the position in all the writer task_map[].
*
* Until the operation is in progress, the data buffer cannot be
* written, because the data is not yet in the buffer.
*
* It's a rolling counter, when reaching ::io_max
* it goes again to 0.
*
* When the caller finish writing the data in the buffer for this
* index, it calls write_sched() and ::writer_index is incremented,
* meaning that the just finished index is scheduled to be written
* to disk.
*
* When this happens a write_sched signal is broadcasted, and all the
* workers can proceed writing the data in this index.
*
* In monothread mode it isn't the task index,
* but the worker index.
*/
unsigned writer_index;
/**
* Counts the error happening in the writers.
*/
int writer_error[IO_WRITER_ERROR_MAX];
/**
* Bandwidth
*/
struct snapraid_bw bw;
};
typedef enum {
IO_OP_NONE = 0, /**< Disk is not accessed. */
IO_OP_READ = 1, /**< Disk is read. */
IO_OP_WRITE = 2 /**< Disk is written. */
} io_op_t;
/**
* Initialize the InputOutput workers with granular directions.
*
* \param io The InputOutput context to initialize.
* \param state The global program state.
* \param io_cache The number of IO buffers for read-ahead and write-behind. 0 for default.
* \param buffer_max The number of data/parity buffers to allocate.
* \param handle_map The map of data disk handles.
* \param handle_max The total number of data disk handles.
* \param data_ops Granular operations for each data disk, or NULL for implicit defaults.
* \param data_reader Callback function pointer for data read tasks.
* \param data_writer Callback function pointer for data write tasks.
* \param parity_handle_map The map of parity disk handles.
* \param parity_handle_max The total number of parity levels/handles.
* \param parity_ops Granular operations for each parity level, or NULL for implicit defaults.
* \param parity_reader Callback function pointer for parity read tasks.
* \param parity_writer Callback function pointer for parity write tasks.
*/
void io_init(struct snapraid_io* io, struct snapraid_state* state,
unsigned io_cache, unsigned buffer_max,
struct snapraid_handle* handle_map, unsigned handle_max,
const io_op_t* data_ops,
void (*data_reader)(struct snapraid_worker*, struct snapraid_task*),
void (*data_writer)(struct snapraid_worker*, struct snapraid_task*),
struct snapraid_parity_handle* parity_handle_map, unsigned parity_handle_max,
const io_op_t* parity_ops,
void (*parity_reader)(struct snapraid_worker*, struct snapraid_task*),
void (*parity_writer)(struct snapraid_worker*, struct snapraid_task*));
/**
* Deinitialize the InputOutput workers.
*/
void io_done(struct snapraid_io* io);
/**
* Start all the worker threads.
*/
extern void (*io_start)(struct snapraid_io* io,
block_off_t blockstart, block_off_t blockmax,
bit_vect_t* block_enabled);
/**
* Stop all the worker threads.
*/
extern void (*io_stop)(struct snapraid_io* io);
/**
* Next read position.
*
* This call starts the reading process.
* It must be called before io_data_read() and io_parity_read().
*
* \param io InputOutput context.
* \param buffer The data buffers to use for this position.
* \return The parity position.
*/
extern block_off_t (*io_read_next)(struct snapraid_io* io, void*** buffer);
/**
* Read a data block.
*
* It must be called exactly ::handle_max times.
*
* \param io InputOutput context.
* \param diskcur The position of the data block in the ::handle_map vector.
* \return The completed task.
*/
extern struct snapraid_task* (*io_data_read)(struct snapraid_io* io, unsigned* diskcur, unsigned* waiting_map, unsigned* waiting_mac);
/**
* Read a parity block.
*
* It must be called exactly ::parity_handle_max times.
*
* \param io InputOutput context.
* \param levcur The position of the parity block in the ::parity_handle_map vector.
* \return The completed task.
*/
extern struct snapraid_task* (*io_parity_read)(struct snapraid_io* io, unsigned* levcur, unsigned* waiting_map, unsigned* waiting_mac);
/**
* Write of a parity block.
*
* It must be called exactly ::parity_handle_max times.
*
* \param io InputOutput context.
* \param levcur The position of the parity block in the ::parity_handle_map vector.
*/
extern void (*io_parity_write)(struct snapraid_io* io, unsigned* levcur, unsigned* waiting_map, unsigned* waiting_mac);
/**
* Preset the write position.
*
* This call starts the write process.
* It must be called before io_parity_write().
*
* \param io InputOutput context.
* \param blockcur The parity position to write.
* \param skip Skip the writes, in case parity doesn't need to be updated.
*/
extern void (*io_write_preset)(struct snapraid_io* io, block_off_t blockcur, int skip);
/**
* Next write position.
*
* This call ends the write process.
* It must be called after io_parity_write().
*
* \param io InputOutput context.
* \param blockcur The parity position to write.
* \param skip Skip the writes, in case parity doesn't need to be updated.
* \param writer_error Return the number of errors. Vector of IO_WRITER_ERROR_MAX elements.
*/
extern void (*io_write_next)(struct snapraid_io* io, block_off_t blockcur, int skip, int* writer_error);
/**
* Refresh the number of cached blocks for all data and parity disks.
*/
extern void (*io_refresh)(struct snapraid_io* io);
/**
* Flush all the writes.
*
* \param writer_error Return the number of errors. Vector of IO_WRITER_ERROR_MAX elements.
*/
extern void (*io_flush)(struct snapraid_io* io, int* writer_error);
/**
* Wait for all scheduled reads to complete.
*
* Completed read-ahead results are retained for later consumption.
*/
extern void (*io_quiesce)(struct snapraid_io* io);
#endif

View file

@ -1,108 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2013 Andrea Mazzoleni
#include "os/portable.h"
#include "util.h"
#include "elem.h"
#include "state.h"
#include "parity.h"
#include "handle.h"
/****************************************************************************/
/* list */
void state_list(struct snapraid_state* state)
{
tommy_node* i;
unsigned file_count;
data_off_t file_size;
unsigned link_count;
file_count = 0;
file_size = 0;
link_count = 0;
msg_progress("Listing...\n");
/* for each disk */
for (i = state->disklist; i != 0; i = i->next) {
tommy_node* j;
struct snapraid_disk* disk = i->data;
/* sort by name */
tommy_list_sort(&disk->filelist, file_path_compare);
/* for each file */
for (j = disk->filelist; j != 0; j = j->next) {
struct snapraid_file* file = j->data;
#if HAVE_LOCALTIME_R
struct tm tm_res;
#endif
struct tm* tm;
time_t t;
++file_count;
file_size += file->size;
if (state->opt.gui_verbose)
log_tag("file:%s:%s:%" PRIu64 ":%" PRIi64 ":%u:%" PRIu64 "\n", disk->name, esc_tag(file->sub), file->size, file->mtime_sec, file->mtime_nsec, file->inode);
t = file->mtime_sec;
#if HAVE_LOCALTIME_R
tm = localtime_r(&t, &tm_res);
#else
tm = localtime(&t);
#endif
printf("%12" PRIu64 " ", file->size);
if (tm) {
printf("%04u/%02u/%02u %02u:%02u", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min);
if (msg_level >= MSG_VERBOSE)
printf(":%02u.%09u", tm->tm_sec, file->mtime_nsec);
printf(" ");
}
printf("%s\n", fmt_term(disk, file->sub));
}
/* sort by name */
tommy_list_sort(&disk->linklist, link_alpha_compare);
/* for each link */
for (j = disk->linklist; j != 0; j = j->next) {
struct snapraid_link* slink = j->data;
const char* type;
switch (slink->flag & FILE_IS_LINK_MASK) {
case FILE_IS_HARDLINK : type = "hardlink"; break;
case FILE_IS_SYMLINK : type = "symlink"; break;
case FILE_IS_SYMDIR : type = "symdir"; break;
case FILE_IS_JUNCTION : type = "junction"; break;
/* LCOV_EXCL_START */
default : type = "unknown"; break;
/* LCOV_EXCL_STOP */
}
++link_count;
if (state->opt.gui_verbose)
log_tag("link_%s:%s:%s:%s\n", type, disk->name, esc_tag(slink->sub), esc_tag(slink->linkto));
printf("%12s ", type);
printf(" ");
if (msg_level >= MSG_VERBOSE)
printf(" ");
printf("%s -> %s\n", fmt_term(disk, slink->sub), fmt_term(disk, slink->linkto));
}
}
msg_status("\n");
msg_status("%8u files, for %" PRIu64 " GB\n", file_count, file_size / GIGA);
msg_status("%8u links\n", link_count);
log_tag("summary:file_count:%u\n", file_count);
log_tag("summary:file_size:%" PRIu64 "\n", file_size);
log_tag("summary:link_count:%u\n", link_count);
log_tag("summary:exit:ok\n");
log_flush();
}

View file

@ -1,267 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2026 Andrea Mazzoleni
#include "os/portable.h"
#include "elem.h"
#include "parity.h"
#include "state.h"
#include "stream.h"
#include "locate.h"
struct snapraid_parity_entry {
uint32_t block_size;
block_off_t low; /**< Lower position in the parity */
block_off_t high; /**< Higher position in the parity */
block_off_t fragments; /**< Number of fragments in the parity */
struct snapraid_file* file;
struct snapraid_disk* disk;
tommy_node node;
};
struct snapraid_locate_info {
block_off_t block_max; /**< Number of blocks in the parity */
data_off_t parity_size; /**< Size in bytes of the parity */
block_off_t tail_block; /**< Number of blocks of the tail of the parity */
block_off_t low_to_free_tail_block; /**< First block that has to be freed */
};
static int parity_entry_compare(const void* void_a, const void* void_b)
{
const struct snapraid_parity_entry* entry_a = void_a;
const struct snapraid_parity_entry* entry_b = void_b;
if (entry_a->high < entry_b->high)
return -1;
if (entry_a->high > entry_b->high)
return 1;
if (entry_a->low < entry_b->low)
return -1;
if (entry_a->low > entry_b->low)
return 1;
return strcmp(entry_a->file->sub, entry_b->file->sub);
}
static void dump_entry(void* void_entry)
{
struct snapraid_parity_entry* entry = void_entry;
printf("%12" PRIu64 " ", entry->low * (uint64_t)entry->block_size);
printf("%12" PRIu64 " ", (entry->high - entry->low + 1) * (uint64_t)entry->block_size);
printf("%8" PRIu64 " ", entry->fragments);
printf("%s\n", fmt_term(entry->disk, entry->file->sub));
}
static void add_size_to_sum(void* arg, void* void_entry)
{
struct snapraid_parity_entry* entry = void_entry;
data_off_t* size_sum = arg;
*size_sum += entry->file->size;
}
static void collect_parity_block_file(uint32_t block_size, struct snapraid_disk* disk, struct snapraid_file* file, tommy_list* file_list, block_off_t low_to_free_tail_block)
{
block_off_t parity_low = 0; /* lower block */
block_off_t parity_high = 0; /* higher block */
block_off_t parity_fragments = 0; /* number of fragments */
for (block_off_t i = 0; i < file->blockmax; ++i) {
block_off_t parity_pos = fs_file2par_find(disk, file, i);
/* check if a valid position is found */
if (parity_pos == POS_NULL) {
/* block not yet allocated */
continue;
}
if (parity_fragments == 0) {
parity_low = parity_pos;
parity_high = parity_pos;
parity_fragments = 1;
} else {
if (parity_pos != parity_high + 1)
++parity_fragments;
parity_high = parity_pos;
}
}
if (parity_fragments == 0)
return; /* not allocated */
if (low_to_free_tail_block > 0 && parity_high < low_to_free_tail_block)
return; /* entry not in the range to free */
/* found a relevant block so add the corresponding file */
struct snapraid_parity_entry* entry = malloc_nofail(sizeof(struct snapraid_parity_entry));
entry->block_size = block_size;
entry->file = file;
entry->disk = disk;
entry->low = parity_low;
entry->high = parity_high;
entry->fragments = parity_fragments;
tommy_list_insert_tail(file_list, &entry->node, entry);
}
static void state_locate_info(struct snapraid_state* state, uint64_t parity_tail, struct snapraid_locate_info* info)
{
uint32_t block_size = state->block_size;
info->block_max = parity_allocated_size(state);
info->parity_size = info->block_max * (uint64_t)block_size;
info->tail_block = (parity_tail / block_size) + (parity_tail % block_size != 0);
if (info->tail_block > info->block_max)
info->low_to_free_tail_block = 0;
else
info->low_to_free_tail_block = info->block_max - info->tail_block;
}
void state_locate(struct snapraid_state* state, uint64_t parity_tail)
{
char buf[64];
uint32_t block_size = state->block_size;
block_off_t low_to_free_tail_block;
printf("SnapRAID locate report:\n");
printf("\n");
if (parity_tail == 0) {
printf("Locate all files\n\n");
low_to_free_tail_block = 0;
} else {
printf("Locate files within the tail of %sB of the parity\n\n", fmt_size(parity_tail, buf, sizeof(buf)));
struct snapraid_locate_info info;
state_locate_info(state, parity_tail, &info);
printf("Current parity size is %sB\n", fmt_size(info.parity_size, buf, sizeof(buf)));
if (info.tail_block > info.block_max) {
printf("Specified tail greater than the parity size! Operate on the full parity\n");
}
low_to_free_tail_block = info.low_to_free_tail_block;
}
msg_progress("Collecting files with offset greater or equal to %" PRIu64 "\n", low_to_free_tail_block * (uint64_t)block_size);
tommy_list files;
tommy_list_init(&files);
for (tommy_node* i = tommy_list_head(&state->disklist); i != 0; i = i->next) {
struct snapraid_disk* disk = i->data;
for (tommy_node* j = tommy_list_head(&disk->filelist); j != 0; j = j->next) {
struct snapraid_file* file = j->data;
collect_parity_block_file(block_size, disk, file, &files, low_to_free_tail_block);
}
}
printf("\n");
if (tommy_list_count(&files) == 0) {
printf("No files located in the specified parity tail.\n");
} else {
tommy_list_sort(&files, parity_entry_compare);
data_off_t total_size_located = 0;
tommy_list_foreach_arg(&files, add_size_to_sum, &total_size_located);
printf("Located data in this range: %sB\n", fmt_size(total_size_located, buf, sizeof(buf)));
printf("\n");
/* |<##################################################################72>|####80>| */
printf(" Offset Span Frags\n");
tommy_list_foreach(&files, dump_entry);
}
tommy_list_foreach(&files, free);
}
void state_locate_mark_tail_blocks_for_resync(struct snapraid_state* state, uint64_t parity_tail)
{
char buf[64];
uint32_t block_size = state->block_size;
block_off_t low_to_free_tail_block;
if (parity_tail == 0) {
printf("Forcing reallocation of all files\n\n");
low_to_free_tail_block = 0;
} else {
msg_progress("Forcing reallocation of all files within the tail of %sB of the parity\n\n", fmt_size(parity_tail, buf, sizeof(buf)));
struct snapraid_locate_info info;
state_locate_info(state, parity_tail, &info);
printf("Current parity size is %sB\n", fmt_size(info.parity_size, buf, sizeof(buf)));
if (info.tail_block > info.block_max) {
printf("Specified tail greater than the parity size! Operate on the full parity\n");
}
low_to_free_tail_block = info.low_to_free_tail_block;
}
msg_progress("Collecting files with offset greater or equal to %" PRIu64 "\n", low_to_free_tail_block * (uint64_t)block_size);
tommy_list files;
tommy_list_init(&files);
for (tommy_node* i = tommy_list_head(&state->disklist); i != 0; i = i->next) {
struct snapraid_disk* disk = i->data;
for (tommy_node* j = tommy_list_head(&disk->filelist); j != 0; j = j->next) {
struct snapraid_file* file = j->data;
collect_parity_block_file(block_size, disk, file, &files, low_to_free_tail_block);
}
}
printf("\n");
if (tommy_list_count(&files) == 0) {
printf("No files located in the specified parity tail.\n");
} else {
/* process all the files partiall or fully overlapping the free zone */
for (tommy_node* j = tommy_list_head(&files); j != 0; j = j->next) {
struct snapraid_parity_entry* entry = j->data;
struct snapraid_file* file = entry->file;
struct snapraid_disk* disk = entry->disk;
/*
* Reallocate the full file, not only the part of in the free zone
* this is required because the files blocks have to be in order in
* in the parity file.
* not reallocating the file head will prevent the reallocation of the file tail
*/
for (block_off_t f = 0; f < file->blockmax; ++f) {
block_off_t parity_pos = fs_file2par_find(disk, file, f);
if (parity_pos == POS_NULL) {
/* block not yet allocated */
continue;
}
struct snapraid_block* block = fs_file2block_get(file, f);
unsigned block_state = block_state_get(block);
if (block_state == BLOCK_STATE_BLK
|| block_state == BLOCK_STATE_REBUILD
) {
/*
* Explicit force-realloc overrides an in-place REBUILD request.
* REP makes the block eligible for the normal reallocation path.
*
* This transition changes persistent block-state semantics. Mark the
* state dirty explicitly rather than relying on the following scan to
* incidentally do so.
*/
block_state_set(block, BLOCK_STATE_REP);
state->need_write = 1;
}
}
}
}
tommy_list_foreach(&files, free);
}

View file

@ -1,17 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2026 Andrea Mazzoleni
#ifndef LOCATE_H
#define LOCATE_H
/****************************************************************************/
/* snapraid */
#include "state.h"
void state_locate(struct snapraid_state* state, uint64_t parity_tail);
void state_locate_mark_tail_blocks_for_resync(struct snapraid_state* state, uint64_t parity_tail);
#endif

View file

@ -1,553 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2025 Andrea Mazzoleni
#include "os/portable.h"
#include "snapraid.h"
#define MODE_DEFAULT 0
#define MODE_SPINDOWN 1
static int build_spindown_argv(int argc, char* argv[], char* spindown_argv[5])
{
char* conf = 0;
int count = 0;
int i;
for (i = 1; i < argc; ++i) {
if (strcmp(argv[i], "-c") == 0 || strcmp(argv[i], "--conf") == 0) {
if (i + 1 < argc) {
conf = argv[++i];
}
} else if (strncmp(argv[i], "-c", 2) == 0 && argv[i][2] != 0) {
conf = argv[i] + 2;
} else if (strncmp(argv[i], "--conf=", 7) == 0) {
conf = argv[i] + 7;
}
}
spindown_argv[count++] = argv[0];
if (conf) {
spindown_argv[count++] = "-c";
spindown_argv[count++] = conf;
}
spindown_argv[count++] = "down";
spindown_argv[count] = 0;
return count;
}
#ifdef _WIN32
#define COMMAND_LINE_MAX 32767
static int needs_quote(const WCHAR* arg)
{
if (*arg == 0)
return 1;
while (*arg) {
if (*arg == L' ' || *arg == L'\t' || *arg == L'"')
return 1;
++arg;
}
return 0;
}
#define charcat(c) \
do { \
if (pos + 1 >= size) { \
errno = E2BIG; \
return -1; \
} \
cmd[pos++] = (c); \
} while (0)
/**
* Append one argument using the Microsoft C runtime command-line
* quoting rules. Use this when building a normal CreateProcessW()
* command line that the target process will parse back into argv[].
*
* Do not use this for cmd.exe /c or batch-script arguments: cmd.exe
* applies an additional command language with different metacharacter
* parsing rules.
*/
static int argcat(WCHAR* cmd, int size, int pos, const WCHAR* arg)
{
int has_quote;
/* space separator */
if (pos != 0)
charcat(L' ');
has_quote = needs_quote(arg);
if (!has_quote) {
while (*arg)
charcat(*arg++);
} else {
/* starting quote */
charcat(L'"');
while (*arg) {
int bl = 0;
while (*arg == L'\\') {
++arg;
++bl;
}
if (*arg == 0) {
/* double backslashes before closing quote */
bl = bl * 2;
while (bl--)
charcat(L'\\');
} else if (*arg == '"') {
/* double backslashes + escape the quote */
bl = bl * 2 + 1;
while (bl--)
charcat(L'\\');
charcat(L'"');
++arg;
} else {
/* normal backslashes */
while (bl--)
charcat(L'\\');
charcat(*arg);
++arg;
}
}
/* ending quote */
charcat(L'"');
}
return pos;
}
static char* argutf8(const WCHAR* arg)
{
size_t len = wcslen(arg);
char* utf8_arg;
DWORD utf8_len;
DWORD res;
utf8_len = WideCharToMultiByte(CP_UTF8, 0, arg, len + 1 /* include final null */, 0, 0, 0, 0);
utf8_arg = malloc(utf8_len);
if (!utf8_arg)
return 0;
res = WideCharToMultiByte(CP_UTF8, 0, arg, len + 1 /* include final null */, utf8_arg, utf8_len, 0, 0);
if (res != utf8_len) {
free(utf8_arg);
return 0;
}
return utf8_arg;
}
/* global variable to store child process handle */
static void* volatile child_process = NULL;
/**
* Safe atomic access helpers for child_process.
*
* The console_handler runs concurrently on an OS-managed thread created by
* the Windows kernel. Because plain writes and standard volatile access do not
* guarantee CPU cache visibility (flushing from store buffers) or prevent CPU/compiler
* out-of-order reordering (due to lack of hardware memory barriers/fences on MinGW),
* we must use Win32 Interlocked APIs to ensure safe, atomic, fence-protected reads
* and writes of the child process handle.
*/
static HANDLE child_process_read(void)
{
return InterlockedCompareExchangePointer(&child_process, NULL, NULL);
}
static void child_process_write(HANDLE handle)
{
InterlockedExchangePointer(&child_process, handle);
}
/* console control handler - forwards Ctrl+C, Ctrl+Break to child */
static BOOL WINAPI console_handler(DWORD ctrl_type)
{
/* if no child, default behavior */
if (child_process_read() == NULL)
return FALSE;
switch (ctrl_type) {
case CTRL_C_EVENT :
case CTRL_BREAK_EVENT :
/*
* Return TRUE to prevent parent termination. The child process
* will receive these events automatically because it's attached
* to the same console, so we don't need to forward them.
*/
return TRUE; /* signal handled, don't terminate parent */
case CTRL_CLOSE_EVENT :
case CTRL_LOGOFF_EVENT :
case CTRL_SHUTDOWN_EVENT :
/*
* Return TRUE to prevent our termination while child handles shutdown.
* The child receives these events automatically (same console).
* Note: Windows will forcibly kill us after a timeout regardless
* of returning TRUE: ~5 seconds for CLOSE_EVENT and LOGOFF_EVENT,
* ~5-20 seconds for SHUTDOWN_EVENT (configurable in registry).
*/
return TRUE; /* signal handled, but Windows will kill us after timeout */
default :
return FALSE;
}
}
int main(int argc, char* argv[])
{
int wide_argc;
WCHAR** wide_argv;
int utf8_argc;
char** utf8_argv;
WCHAR app_buffer[COMMAND_LINE_MAX];
WCHAR cmd_buffer[COMMAND_LINE_MAX];
DWORD res;
int i;
int pos;
int mode;
int lock_options;
int ret;
(void)argc;
(void)argv;
res = GetModuleFileNameW(NULL, app_buffer, COMMAND_LINE_MAX);
if (res == 0 || res >= COMMAND_LINE_MAX) {
exit(EXIT_FAILURE);
}
wide_argv = CommandLineToArgvW(GetCommandLineW(), &wide_argc);
if (!wide_argv) {
exit(EXIT_FAILURE);
}
utf8_argc = 0;
utf8_argv = malloc((wide_argc + 1) * sizeof(void*));
if (!utf8_argv) {
exit(EXIT_FAILURE);
}
pos = argcat(cmd_buffer, COMMAND_LINE_MAX, 0, app_buffer);
if (pos < 0) {
exit(EXIT_FAILURE);
}
utf8_argv[0] = argutf8(app_buffer);
if (!utf8_argv[0]) {
exit(EXIT_FAILURE);
}
utf8_argc = 1;
mode = MODE_DEFAULT;
lock_options = 0;
for (i = 1; i < wide_argc; i++) {
if (wcscmp(wide_argv[i], L"--lock-options") == 0)
lock_options = 1;
if (wcscmp(wide_argv[i], L"-s") == 0 || wcscmp(wide_argv[i], L"--spin-down-on-error") == 0) {
mode = MODE_SPINDOWN;
} else {
pos = argcat(cmd_buffer, COMMAND_LINE_MAX, pos, wide_argv[i]);
if (pos < 0) {
exit(EXIT_FAILURE);
}
utf8_argv[utf8_argc] = argutf8(wide_argv[i]);
if (!utf8_argv[utf8_argc]) {
exit(EXIT_FAILURE);
}
++utf8_argc;
}
}
utf8_argv[utf8_argc] = 0;
cmd_buffer[pos] = 0;
if (mode == MODE_SPINDOWN && lock_options) {
fprintf(stderr, "The --spin-down-on-error option cannot be used with --lock-options.\n");
exit(EXIT_FAILURE);
}
LocalFree(wide_argv);
if (mode == MODE_DEFAULT) {
ret = snapraid_main(utf8_argc, utf8_argv);
} else {
STARTUPINFOW si;
PROCESS_INFORMATION pi;
DWORD wait;
/* install console control handler */
if (!SetConsoleCtrlHandler(console_handler, TRUE)) {
fprintf(stderr, "Failed to set console handler\n");
exit(EXIT_FAILURE);
}
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
if (!CreateProcessW(app_buffer, cmd_buffer, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
fprintf(stderr, "Failed to exec SnapRAID\n");
exit(EXIT_FAILURE);
}
/* store child process handle for signal handler */
child_process_write(pi.hProcess);
wait = WaitForSingleObject(pi.hProcess, INFINITE);
if (wait != WAIT_OBJECT_0) {
fprintf(stderr, "WaitForSingleObject failed: %lu\n", (unsigned long)GetLastError());
TerminateProcess(pi.hProcess, 1);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return 1;
}
/* clear child process handle */
child_process_write(NULL);
if (!GetExitCodeProcess(pi.hProcess, &res)) {
fprintf(stderr, "GetExitCodeProcess failed: %lu\n", (unsigned long)GetLastError());
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return 1;
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
ret = res;
if (ret != 0) {
char* spindown_argv[5];
int spindown_argc = build_spindown_argv(utf8_argc, utf8_argv, spindown_argv);
/* sync all disks */
printf("Flush...\n");
if (sync() != 0)
printf("WARNING! Failed to flush disks!\n");
snapraid_main(spindown_argc, spindown_argv);
}
}
for (i = 0; i < utf8_argc; ++i)
free(utf8_argv[i]);
free(utf8_argv);
return ret;
}
#else
char full_argv0[PATH_MAX];
const char* get_argv0(const char* argv0)
{
ssize_t len = readlink("/proc/self/exe", full_argv0, sizeof(full_argv0) - 1);
if (len != -1) {
full_argv0[len] = '\0';
return full_argv0;
} else {
#ifdef __APPLE__
uint32_t size = sizeof(full_argv0);
if (_NSGetExecutablePath(full_argv0, &size) == 0)
return full_argv0;
#endif
}
return argv0;
}
/* global variable to store child PID for signal handler */
static volatile sig_atomic_t child_pid = 0;
/* signal handler that forwards signals to child */
/* LCOV_EXCL_START */
static void forward_signal(int sig)
{
if (child_pid > 0) {
kill((pid_t)child_pid, sig);
}
}
/* LCOV_EXCL_STOP */
int main(int argc, char* argv[])
{
int mode;
int lock_options;
int i, j;
int ret;
mode = MODE_DEFAULT;
lock_options = 0;
j = 1;
for (i = 1; i < argc; ++i) {
if (strcmp(argv[i], "--lock-options") == 0)
lock_options = 1;
if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--spin-down-on-error") == 0) {
mode = MODE_SPINDOWN;
} else {
argv[j] = argv[i];
++j;
}
}
argc = j;
argv[argc] = 0;
if (mode == MODE_SPINDOWN && lock_options) {
fprintf(stderr, "The --spin-down-on-error option cannot be used with --lock-options.\n");
exit(EXIT_FAILURE);
}
if (mode == MODE_DEFAULT) {
ret = snapraid_main(argc, argv);
} else {
struct sigaction sa;
/* set up signal handler to ignore signals */
sa.sa_handler = forward_signal;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART; /* restart interrupted system calls */
/* install forwarding handler for signals */
sigaction(SIGINT, &sa, NULL); /* Ctrl+C */
sigaction(SIGQUIT, &sa, NULL); /* Ctrl+\ */
sigaction(SIGTERM, &sa, NULL); /* termination */
sigaction(SIGHUP, &sa, NULL); /* hangup */
sigaction(SIGUSR1, &sa, NULL); /* user-defined 1 */
sigaction(SIGUSR2, &sa, NULL); /* user-defined 2 */
sigset_t set, oldset;
sigemptyset(&set);
sigaddset(&set, SIGINT);
sigaddset(&set, SIGQUIT);
sigaddset(&set, SIGTERM);
sigaddset(&set, SIGHUP);
sigaddset(&set, SIGUSR1);
sigaddset(&set, SIGUSR2);
/* block signals to prevent signal race before child_pid is set */
sigprocmask(SIG_BLOCK, &set, &oldset);
pid_t pid = fork();
if (pid == -1) {
/* LCOV_EXCL_START */
perror("Failed to fork SnapRAID");
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (pid == 0) {
/* child process */
/* isolate child in its own process group to prevent double signal delivery from terminal */
setpgid(0, 0);
/* restore default signal handlers */
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
signal(SIGHUP, SIG_DFL);
signal(SIGUSR1, SIG_DFL);
signal(SIGUSR2, SIG_DFL);
/* unblock signals in child */
sigprocmask(SIG_SETMASK, &oldset, NULL);
execvp(get_argv0(argv[0]), argv);
/* here it's an error */
/* LCOV_EXCL_START */
perror("Failed to exec SnapRAID");
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
} else {
/* parent process */
int status;
/* set child process group in parent to prevent race condition */
setpgid(pid, pid);
/* store child PID so signal handler can forward signals */
child_pid = pid;
/* unblock signals in parent */
sigprocmask(SIG_SETMASK, &oldset, NULL);
/*
* First wait for child termination without reaping (WNOWAIT).
* The child enters zombie state, holding its PID reserved in the kernel
* so no newly created process can receive the same PID. We clear
* child_pid before the final waitpid() reap so the signal forwarder
* never sends signals to a recycled PID.
*/
siginfo_t info;
int wret;
do {
memset(&info, 0, sizeof(info));
wret = waitid(P_PID, (id_t)pid, &info, WEXITED | WNOWAIT);
} while (wret == -1 && errno == EINTR);
if (wret == -1) {
/* LCOV_EXCL_START */
perror("Failed to wait for SnapRAID");
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
/* clear child PID while PID is still reserved in zombie state */
child_pid = 0;
do {
ret = waitpid(pid, &status, 0);
} while (ret == -1 && errno == EINTR); /* retry if interrupted by signal */
if (ret == -1) {
/* LCOV_EXCL_START */
perror("Failed to reap SnapRAID");
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
/* restore default signal handlers */
signal(SIGINT, SIG_DFL);
signal(SIGQUIT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
signal(SIGHUP, SIG_DFL);
signal(SIGUSR1, SIG_DFL);
signal(SIGUSR2, SIG_DFL);
if (WIFEXITED(status)) {
ret = WEXITSTATUS(status);
} else if (WIFSIGNALED(status)) {
/* terminated by signal */
ret = 128 + WTERMSIG(status);
} else {
ret = -1;
}
if (ret != 0) {
char* spindown_argv[5];
int spindown_argc = build_spindown_argv(argc, argv, spindown_argv);
/* ignore sigpipe to allow spindown even if the terminal is closed */
signal(SIGPIPE, SIG_IGN);
/* in *nix DO NOT CALL sync() because we use syncfs() in all single disks befode the down command */
snapraid_main(spindown_argc, spindown_argv);
}
}
}
return ret;
}
#endif

View file

@ -1,203 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
#include "os/portable.h"
#include "support.h"
#include "memory.h"
/****************************************************************************/
/* memory */
/**
* Cumulative amount of memory allocated.
*/
static size_t mcounter;
#if HAVE_THREAD
static int memory_is_single_thread;
void memory_single_thread(int single_thread)
{
memory_is_single_thread = single_thread;
}
static inline void malloc_counter_inc(size_t inc)
{
if (tommy_likely(memory_is_single_thread))
mcounter += inc;
else
__atomic_fetch_add(&mcounter, inc, __ATOMIC_RELAXED);
}
size_t malloc_counter_get(void)
{
if (tommy_likely(memory_is_single_thread))
return mcounter;
return __atomic_load_n(&mcounter, __ATOMIC_RELAXED);
}
#else
void memory_single_thread(int single_thread)
{
(void)single_thread;
}
static inline void malloc_counter_inc(size_t inc)
{
mcounter += inc;
}
size_t malloc_counter_get(void)
{
return mcounter;
}
#endif
/* LCOV_EXCL_START */
static ssize_t malloc_print(int f, const char* str)
{
ssize_t len = 0;
while (str[len])
++len;
return write(f, str, len);
}
/* LCOV_EXCL_STOP */
/* LCOV_EXCL_START */
static ssize_t malloc_printn(int f, size_t value)
{
char buf[32];
int i;
if (!value)
return write(f, "0", 1);
i = sizeof(buf);
while (value) {
buf[--i] = (value % 10) + '0';
value /= 10;
}
return write(f, buf + i, sizeof(buf) - i);
}
/* LCOV_EXCL_STOP */
/* LCOV_EXCL_START */
void malloc_fail(size_t size)
{
/* don't use printf to avoid any possible extra allocation */
int f = 2; /* stderr */
malloc_print(f, "Failed for Low Memory!\n");
malloc_print(f, "Allocating ");
malloc_printn(f, size);
malloc_print(f, " bytes.\n");
malloc_print(f, "Already allocated ");
malloc_printn(f, malloc_counter_get());
malloc_print(f, " bytes.\n");
if (sizeof(void*) == 4) {
malloc_print(f, "You are currently using a 32 bits executable.\n");
malloc_print(f, "If you have more than 4GB of memory, please upgrade to a 64 bits one.\n");
}
}
/* LCOV_EXCL_STOP */
void* malloc_nofail(size_t size)
{
void* ptr = malloc(size ? size : 1);
if (!ptr) {
/* LCOV_EXCL_START */
malloc_fail(size);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
malloc_counter_inc(size);
return ptr;
}
void* realloc_nofail(void* ptr, size_t size)
{
/* keep zero-size requests allocated, as in malloc_nofail() */
void* new_ptr = realloc(ptr, size ? size : 1);
if (!new_ptr) {
/* LCOV_EXCL_START */
malloc_fail(size);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
malloc_counter_inc(size);
return new_ptr;
}
void* nalloc_nofail(size_t count, size_t size)
{
if (size != 0 && count > SIZE_MAX / size) {
log_fatal(EINTERNAL, "Allocation size overflow\n");
os_abort();
}
size *= count;
void* ptr = malloc(size ? size : 1);
if (!ptr) {
/* LCOV_EXCL_START */
malloc_fail(size);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
malloc_counter_inc(size);
return ptr;
}
void* calloc_nofail(size_t count, size_t size)
{
if (size != 0 && count > SIZE_MAX / size) {
log_fatal(EINTERNAL, "Allocation size overflow\n");
os_abort();
}
void* ptr = calloc(count ? count : 1, size ? size : 1);
if (!ptr) {
/* LCOV_EXCL_START */
malloc_fail(count * size);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
malloc_counter_inc(count * size);
return ptr;
}
char* strdup_nofail(const char* str)
{
size_t size = strlen(str) + 1;
char* ptr = malloc_nofail(size);
memcpy(ptr, str, size);
return ptr;
}
char* strndup_nofail(const char* str, size_t size)
{
char* ptr = malloc_nofail(size + 1);
memcpy(ptr, str, size);
ptr[size] = 0;
return ptr;
}

View file

@ -1,62 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
#ifndef MEMORY_H
#define MEMORY_H
/****************************************************************************/
/* memory */
/**
* Return the size of the cumulative allocated memory.
*/
size_t malloc_counter_get(void);
/**
* Enable or disable single-thread mode for memory counters.
*/
void memory_single_thread(int single_thread);
/**
* Safe malloc.
* If no memory is available, it aborts.
*/
void* malloc_nofail(size_t size);
/**
* Safe realloc.
* If no memory is available, it aborts.
*/
void* realloc_nofail(void* ptr, size_t size);
/**
* Safe malloc with calloc calling arguments.
* If no memory is available, it aborts.
*/
void* nalloc_nofail(size_t count, size_t size);
/**
* Safe calloc.
* If no memory is available, it aborts.
*/
void* calloc_nofail(size_t count, size_t size);
/**
* Safe strdup.
* If no memory is available, it aborts.
*/
char* strdup_nofail(const char* str);
/**
* Safe strndup with known length.
* If no memory is available, it aborts.
*/
char* strndup_nofail(const char* str, size_t size);
/**
* Helper for printing an error about a failed allocation.
*/
void malloc_fail(size_t size);
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,254 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2015 Andrea Mazzoleni
#include "os/portable.h"
#include "stream.h"
#include "support.h"
#define STREAM_MAX 8
#define BUFFER_MAX 64
#define STR_MAX 128
void test(int advise_mode)
{
struct stream* s;
char file[32];
unsigned char buffer[BUFFER_MAX];
char str[STR_MAX];
unsigned i, j;
uint32_t u32 = -1L;
uint64_t u64 = -1LL;
uint32_t put_crc_stored;
crc32c_init();
s = sopen_multi_write(STREAM_MAX, advise_mode | STREAM_FLAGS_CRC);
for (i = 0; i < STREAM_MAX; ++i) {
snprintf(file, sizeof(file), "stream%u.bin", i);
remove(file);
if (sopen_multi_file(s, i, file) != 0) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
for (j = 0; j < 256; ++j) {
if (sputc(j, s) != 0) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
for (j = 0; j < 32; ++j) {
if (sputb32(u32 >> j, s) != 0) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
for (j = 0; j < 64; ++j) {
if (sputb64(u64 >> j, s) != 0) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
for (j = 0; j < BUFFER_MAX; ++j) {
memset(buffer, j, j);
if (swrite(buffer, j, s) != 0) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
for (j = 1; j < STR_MAX; ++j) {
memset(str, ' ' + j, j - 1);
str[j - 1] = 0;
if (sputbs(str, s) != 0) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
put_crc_stored = scrc(s);
if (sputble32(put_crc_stored, s) != 0) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (sclose(s) != 0) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
for (i = 0; i < STREAM_MAX; ++i) {
uint32_t get_crc_stored;
uint32_t get_crc_computed;
snprintf(file, sizeof(file), "stream%u.bin", i);
s = sopen_read(file, advise_mode | STREAM_FLAGS_CRC);
if (s == 0) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
for (j = 0; j < 256; ++j) {
int c = sgetc(s);
if (c == EOF || (unsigned char)c != j) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
for (j = 0; j < 32; ++j) {
uint32_t v32;
if (sgetb32(s, &v32) != 0 || v32 != (u32 >> j)) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
for (j = 0; j < 64; ++j) {
uint64_t v64;
if (sgetb64(s, &v64) != 0 || v64 != (u64 >> j)) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
for (j = 1; j < BUFFER_MAX; ++j) {
char copy[BUFFER_MAX];
memset(buffer, j, j);
if (sread(s, copy, j) != 0 || memcmp(copy, buffer, j) != 0) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
for (j = 1; j < STR_MAX; ++j) {
char copy[STR_MAX];
memset(str, ' ' + j, j - 1);
str[j - 1] = 0;
if (sgetbs(s, copy, sizeof(copy)) != (ssize_t)(j - 1) || strcmp(copy, str) != 0) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
/* get the computed CRC *before* reading the stored one */
get_crc_computed = scrc(s);
if (sgetble32(s, &get_crc_stored) != 0) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (get_crc_stored != put_crc_stored) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (get_crc_stored != get_crc_computed) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (sclose(s) != 0) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
for (i = 0; i < STREAM_MAX; ++i) {
uint32_t get_crc_stored;
uint32_t get_crc_computed;
unsigned char buf[4];
snprintf(file, sizeof(file), "stream%u.bin", i);
s = sopen_read(file, advise_mode | STREAM_FLAGS_CRC);
if (s == 0) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (sdeplete(s, buf) != 0) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
/* get the stored crc from the last four bytes */
get_crc_stored = buf[0] | (uint32_t)buf[1] << 8 | (uint32_t)buf[2] << 16 | (uint32_t)buf[3] << 24;
if (get_crc_stored != put_crc_stored) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
/* get the computed CRC *after* reading the stored one */
get_crc_computed = scrc(s);
/* adjust the stored crc to include itself */
get_crc_stored = crc32c(get_crc_stored, buf, 4);
if (get_crc_stored != get_crc_computed) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (sclose(s) != 0) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
}
int main(void)
{
unsigned i;
lock_init();
for (i = 1; i <= 16; ++i) {
/* test with different stream buffer size */
STREAM_SIZE = i;
printf("Test stream buffer size %u\n", i);
test(ADVISE_DEFAULT);
}
STREAM_SIZE = 64 * 1024;
for (i = ADVISE_SEQUENTIAL; i <= ADVISE_DISCARD_WINDOW; ++i) {
printf("Test stream advise mode %u\n", i);
test(i);
}
return 0;
}

View file

@ -1,786 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
#include "os/portable.h"
#include "support.h"
/****************************************************************************/
/* random */
/**
* Pseudo random number generator.
*/
unsigned long long seed = 0;
size_t rnd(size_t max)
{
seed = seed * 6364136223846793005LL + 1442695040888963407LL;
return (seed >> 32) % max;
}
size_t rndnz(size_t max)
{
if (max <= 1)
return 1;
else
return rnd(max - 1) + 1;
}
void rndnz_range(unsigned char* data, ssize_t size)
{
ssize_t i;
for (i = 0; i < size; ++i)
data[i] = rndnz(256);
}
void rndnz_damage(unsigned char* data, ssize_t size)
{
ssize_t i;
/* corrupt ensuring always different data */
for (i = 0; i < size; ++i) {
unsigned char c;
do {
c = rndnz(256);
} while (c == data[i]);
data[i] = c;
}
}
char CHARSET[] = "qwertyuiopasdfghjklzxcvbnm1234567890 .-+";
#define CHARSET_LEN (sizeof(CHARSET) - 1)
void rnd_name(char* file)
{
ssize_t l = 1 + rnd(20);
while (l) {
*file++ = CHARSET[rnd(CHARSET_LEN)];
--l;
}
*file = 0;
}
/****************************************************************************/
/* file */
int file_cmp(const void* a, const void* b)
{
return strcmp(a, b);
}
int fallback(int f, struct stat* st)
{
#if HAVE_FUTIMENS
struct timespec tv[2];
#else
struct timeval tv[2];
#endif
int ret;
#if HAVE_FUTIMENS /* futimens() is preferred because it gives nanosecond precision */
tv[0].tv_sec = st->st_mtime;
if (STAT_NSEC(st) != STAT_NSEC_INVALID)
tv[0].tv_nsec = STAT_NSEC(st);
else
tv[0].tv_nsec = 0;
tv[1].tv_sec = tv[0].tv_sec;
tv[1].tv_nsec = tv[0].tv_nsec;
ret = futimens(f, tv);
#elif HAVE_FUTIMES /* fallback to futimes() if nanosecond precision is not available */
tv[0].tv_sec = st->st_mtime;
if (STAT_NSEC(st) != STAT_NSEC_INVALID)
tv[0].tv_usec = STAT_NSEC(st) / 1000;
else
tv[0].tv_usec = 0;
tv[1].tv_sec = tv[0].tv_sec;
tv[1].tv_usec = tv[0].tv_usec;
ret = futimes(f, tv);
#elif HAVE_FUTIMESAT /* fallback to futimesat() for Solaris, it only has futimesat() */
tv[0].tv_sec = st->st_mtime;
if (STAT_NSEC(st) != STAT_NSEC_INVALID)
tv[0].tv_usec = STAT_NSEC(st) / 1000;
else
tv[0].tv_usec = 0;
tv[1].tv_sec = tv[0].tv_sec;
tv[1].tv_usec = tv[0].tv_usec;
ret = futimesat(f, 0, tv);
#else
#error No function available to set file timestamps
#endif
return ret;
}
/****************************************************************************/
/* cmd */
/**
* Create a file with random content.
* - If the file exists it's rewritten, but avoiding to truncating it to 0.
*/
void cmd_generate_file(const char* path, ssize_t size)
{
unsigned char* data;
int f;
/* remove the existing file/symlink if any */
if (remove(path) != 0) {
if (errno != ENOENT) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error removing file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
} else {
/* don't truncate files to 0 size to avoid ZERO file size protection */
++size;
}
data = malloc(size);
/*
* We don't write zero bytes because we want to test
* the recovering of new files, after an aborted sync
* If the files contains full blocks at zero
* this is an impossible condition to recover
* because we cannot differentiate between an unused block
* and a file filled with 0
*/
rndnz_range(data, size);
f = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_NOFOLLOW, 0600);
if (f < 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error creating file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (write(f, data, size) != size) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error writing file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (close(f) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error closing file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
free(data);
}
/**
* Create a symlink.
* - If the file already exists, it's removed.
*/
void cmd_generate_symlink(const char* path, const char* linkto)
{
/* remove the existing file/symlink if any */
if (remove(path) != 0) {
if (errno != ENOENT) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error removing file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
if (symlink(linkto, path) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error writing symlink %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
/**
* Create a file or a symlink with a random name.
*/
void cmd_generate(const char* tag, int disk, ssize_t size)
{
char path[PATH_MAX];
char* file;
snprintf(path, sizeof(path), "bench/%s%d/", tag, disk);
file = path + strlen(path);
/* add a directory */
*file++ = 'a' + rnd(2);
*file = 0;
/* create it */
if (mkdir(path, 0777) != 0) {
if (errno != EEXIST) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error creating directory %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
*file++ = '/';
while (1) {
/* add a random file */
rnd_name(file);
/* skip some invalid file name, see http://en.wikipedia.org/wiki/Filename */
if (strcmp(file, ".") == 0
|| strcmp(file, "..") == 0
|| strcmp(file, "prn") == 0
|| strcmp(file, "con") == 0
|| strcmp(file, "nul") == 0
|| strcmp(file, "aux") == 0
|| file[0] == ' '
|| file[strlen(file) - 1] == ' '
|| file[strlen(file) - 1] == '.'
) {
continue;
}
break;
}
#ifndef WIN32 /* Windows XP doesn't support symlinks */
if (rnd(32) == 0) {
/* symlink */
char linkto[PATH_MAX];
rnd_name(linkto);
cmd_generate_symlink(path, linkto);
} else
#endif
{
/* file */
cmd_generate_file(path, size);
}
}
/**
* Write a partially a file.
* - The file must exist.
* - The file size is not changed.
* - The written data may be equal or not at the already existing one.
* - If it's a symlink nothing is done.
*/
void cmd_write(const char* path, ssize_t size)
{
struct stat st;
if (lstat(path, &st) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error accessing %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (S_ISREG(st.st_mode)) {
unsigned char* data;
off_t off;
int f;
/* not over the end */
if (size > st.st_size)
size = st.st_size;
/* start at random position inside the file */
if (size < st.st_size)
off = rnd(st.st_size - size);
else
off = 0;
data = malloc(size);
rndnz_range(data, size);
f = open(path, O_WRONLY | O_BINARY | O_NOFOLLOW);
if (f < 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error creating file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (lseek(f, off, SEEK_SET) != off) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error seeking file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (write(f, data, size) != size) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error writing file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (close(f) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error closing file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
free(data);
}
}
/**
* Damage a file.
* - The file must exist.
* - The file size is not changed.
* - The written data is SURELY different than the already existing one.
* - The file timestamp is NOT modified.
* - If it's a symlink nothing is done.
*/
void cmd_damage(const char* path, ssize_t size)
{
struct stat st;
/*
* Here a 0 size means to change nothing
* as also the timestamp should not be changed
*/
if (!size)
return;
if (lstat(path, &st) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error accessing %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (st.st_size == 0)
return;
if (S_ISREG(st.st_mode)) {
off_t off;
unsigned char* data;
int f;
/* not over the end */
if (size > st.st_size)
size = st.st_size;
/* start at random position inside the file */
if (size < st.st_size)
off = rnd(st.st_size - size);
else
off = 0;
data = malloc(size);
f = open(path, O_RDWR | O_BINARY | O_NOFOLLOW);
if (f < 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error creating file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (lseek(f, off, SEEK_SET) != off) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error seeking file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (read(f, data, size) != size) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error writing file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
rndnz_damage(data, size);
if (lseek(f, off, SEEK_SET) != off) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error seeking file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (write(f, data, size) != size) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error writing file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (fallback(f, &st) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error setting time for file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (close(f) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error closing file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
free(data);
}
}
/**
* Append to a file.
* - The file must exist.
* - If it's a symlink nothing is done.
*/
void cmd_append(const char* path, ssize_t size)
{
struct stat st;
if (lstat(path, &st) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error accessing %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (S_ISREG(st.st_mode)) {
unsigned char* data;
int f;
data = malloc(size);
rndnz_range(data, size);
f = open(path, O_WRONLY | O_APPEND | O_BINARY | O_NOFOLLOW);
if (f < 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error opening file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (write(f, data, size) != size) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error writing file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (close(f) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error closing file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
free(data);
}
}
/**
* Truncate a file.
* - The file must exist.
* - The file is NEVER truncated to 0.
* - If it's a symlink nothing is done.
*/
void cmd_truncate(const char* path, ssize_t size)
{
struct stat st;
if (lstat(path, &st) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error accessing %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (S_ISREG(st.st_mode)) {
off_t off;
int f;
/* if file is empty, just rewrite it */
if (st.st_size == 0) {
size = 0;
} else {
/* don't truncate files to 0 size to avoid ZERO file size protection */
if (size >= st.st_size)
size = st.st_size - 1;
}
off = st.st_size - size;
f = open(path, O_WRONLY | O_BINARY | O_NOFOLLOW);
if (f < 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error opening file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (ftruncate(f, off) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error truncating file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (close(f) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error closing file %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
}
/**
* Delete a file.
* - The file must exist.
*/
void cmd_delete(const char* path)
{
if (remove(path) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error removing %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
/**
* Change a file. Or deleted/truncated/append/created.
* - The file must exist.
*/
void cmd_change(const char* path, ssize_t size)
{
struct stat st;
if (!size)
return;
if (lstat(path, &st) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error accessing %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (S_ISLNK(st.st_mode)) {
/* symlink */
if (rnd(2) == 0) {
/* delete */
if (remove(path) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error removing %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
} else {
/* recreate */
char linkto[PATH_MAX];
if (remove(path) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error removing %s\n", path);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
rnd_name(linkto);
cmd_generate_symlink(path, linkto);
}
} else if (S_ISREG(st.st_mode)) {
size_t r;
r = rnd(4);
if (r == 0) {
cmd_write(path, size);
} else if (r == 1) {
cmd_append(path, size);
} else if (r == 2) {
cmd_truncate(path, size);
} else {
cmd_delete(path);
}
}
}
void help(void)
{
printf("Test for " PACKAGE " v" VERSION " by Andrea Mazzoleni, " PACKAGE_URL "\n");
printf("Usage:\n");
printf("\tmktest generate SEED DISK_TAG DISK_NUM FILE_NUM FILE_SIZE\n");
printf("\tmktest damage SEED COUNT SIZE FILE\n");
printf("\tmktest write SEED COUNT SIZE FILE\n");
printf("\tmktest change SEED SIZE FILE\n");
printf("\tmktest append SEED SIZE FILE\n");
printf("\tmktest truncate SEED SIZE FILE\n");
}
int main(int argc, char* argv[])
{
int i, j, b;
lock_init();
if (argc < 2) {
help();
exit(EXIT_SUCCESS);
}
if (strcmp(argv[1], "generate") == 0) {
int disk, file, size;
const char* tag;
if (argc != 7) {
/* LCOV_EXCL_START */
help();
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
seed = atoi(argv[2]);
tag = argv[3];
disk = atoi(argv[4]);
file = atoi(argv[5]);
size = atoi(argv[6]);
for (i = 0; i < disk; ++i) {
for (j = 0; j < file; ++j) {
if (j == 0)
/* create at least a big one */
cmd_generate(tag, i + 1, size);
else if (j == 1)
/* create at least an empty one */
cmd_generate(tag, i + 1, 0);
else
cmd_generate(tag, i + 1, rnd(size));
}
}
} else if (strcmp(argv[1], "write") == 0) {
int fail, size;
if (argc < 6) {
/* LCOV_EXCL_START */
help();
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
seed = atoi(argv[2]);
fail = atoi(argv[3]);
size = atoi(argv[4]);
b = 5;
/* sort the file names */
qsort(&argv[b], argc - b, sizeof(argv[b]), file_cmp);
for (i = b; i < argc; ++i)
for (j = 0; j < fail; ++j)
cmd_write(argv[i], rndnz(size));
} else if (strcmp(argv[1], "damage") == 0) {
int fail, size;
if (argc < 6) {
/* LCOV_EXCL_START */
help();
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
seed = atoi(argv[2]);
fail = atoi(argv[3]);
size = atoi(argv[4]);
b = 5;
/* sort the file names */
qsort(&argv[b], argc - b, sizeof(argv[b]), file_cmp);
for (i = b; i < argc; ++i)
for (j = 0; j < fail; ++j)
cmd_damage(argv[i], rndnz(size)); /* at least one byte */
} else if (strcmp(argv[1], "append") == 0) {
int size;
if (argc < 5) {
/* LCOV_EXCL_START */
help();
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
seed = atoi(argv[2]);
size = atoi(argv[3]);
b = 4;
/* sort the file names */
qsort(&argv[b], argc - b, sizeof(argv[b]), file_cmp);
for (i = b; i < argc; ++i)
cmd_append(argv[i], rndnz(size)); /* at least one byte */
} else if (strcmp(argv[1], "truncate") == 0) {
int size;
if (argc < 5) {
/* LCOV_EXCL_START */
help();
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
seed = atoi(argv[2]);
size = atoi(argv[3]);
b = 4;
/* sort the file names */
qsort(&argv[b], argc - b, sizeof(argv[b]), file_cmp);
for (i = b; i < argc; ++i)
cmd_truncate(argv[i], rnd(size));
} else if (strcmp(argv[1], "change") == 0) {
int size;
if (argc < 5) {
/* LCOV_EXCL_START */
help();
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
seed = atoi(argv[2]);
size = atoi(argv[3]);
b = 4;
/* sort the file names */
qsort(&argv[b], argc - b, sizeof(argv[b]), file_cmp);
for (i = b; i < argc; ++i)
cmd_change(argv[i], rnd(size));
} else {
/* LCOV_EXCL_START */
help();
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
lock_done();
return 0;
}

View file

@ -1,140 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
/*
* Derivative work from MurmorHash3.cpp revision r136
*
* SMHasher & MurmurHash
* http://code.google.com/p/smhasher/
*
* Exact source used as reference:
* http://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp?spec=svn136&r=136
*/
// MurmurHash3 was written by Austin Appleby, and is placed in the public
// domain. The author hereby disclaims copyright to this source code.
/* finalization mix - force all bits of a hash block to avalanche */
static inline uint32_t fmix32(uint32_t h)
{
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
return h;
}
/**
* Non-static variables are intentionally used instead of static const
* because keeping these constants in CPU registers yields measurably
* higher throughput than using 32-bit immediate constants in imul.
*/
uint32_t c1 = 0x239b961b;
uint32_t c2 = 0xab0e9789;
uint32_t c3 = 0x38b34ae5;
uint32_t c4 = 0xa1e38b93;
static void MurmurHash3_x86_128(const void* data, size_t size, const uint8_t* seed, void* digest)
{
const uint8_t* p;
const uint8_t* end;
size_t size_remainder;
uint32_t h1, h2, h3, h4;
h1 = util_read32(seed + 0);
h2 = util_read32(seed + 4);
h3 = util_read32(seed + 8);
h4 = util_read32(seed + 12);
p = data;
end = p + (size & ~15);
/* body */
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC unroll 8
#elif defined(__clang__)
#pragma unroll 8
#endif
while (p < end) {
uint32_t k1 = util_read32(p + 0);
uint32_t k2 = util_read32(p + 4);
uint32_t k3 = util_read32(p + 8);
uint32_t k4 = util_read32(p + 12);
k1 *= c1; k1 = util_rotl32(k1, 15); k1 *= c2; h1 ^= k1;
h1 = util_rotl32(h1, 19); h1 += h2; h1 = h1 * 5 + 0x561ccd1b;
k2 *= c2; k2 = util_rotl32(k2, 16); k2 *= c3; h2 ^= k2;
h2 = util_rotl32(h2, 17); h2 += h3; h2 = h2 * 5 + 0x0bcaa747;
k3 *= c3; k3 = util_rotl32(k3, 17); k3 *= c4; h3 ^= k3;
h3 = util_rotl32(h3, 15); h3 += h4; h3 = h3 * 5 + 0x96cd1c35;
k4 *= c4; k4 = util_rotl32(k4, 18); k4 *= c1; h4 ^= k4;
h4 = util_rotl32(h4, 13); h4 += h1; h4 = h4 * 5 + 0x32ac3b17;
p += 16;
}
/* tail */
size_remainder = size & 15;
if (size_remainder != 0) {
const uint8_t* tail = p;
uint32_t k1 = 0;
uint32_t k2 = 0;
uint32_t k3 = 0;
uint32_t k4 = 0;
switch (size_remainder) {
case 15 : k4 ^= (uint32_t)tail[14] << 16; /* fallthrough */
case 14 : k4 ^= (uint32_t)tail[13] << 8; /* fallthrough */
case 13 : k4 ^= (uint32_t)tail[12] << 0; /* fallthrough */
k4 *= c4; k4 = util_rotl32(k4, 18); k4 *= c1; h4 ^= k4;
/* fallthrough */
case 12 : k3 ^= (uint32_t)tail[11] << 24; /* fallthrough */
case 11 : k3 ^= (uint32_t)tail[10] << 16; /* fallthrough */
case 10 : k3 ^= (uint32_t)tail[ 9] << 8; /* fallthrough */
case 9 : k3 ^= (uint32_t)tail[ 8] << 0; /* fallthrough */
k3 *= c3; k3 = util_rotl32(k3, 17); k3 *= c4; h3 ^= k3;
/* fallthrough */
case 8 : k2 ^= (uint32_t)tail[ 7] << 24; /* fallthrough */
case 7 : k2 ^= (uint32_t)tail[ 6] << 16; /* fallthrough */
case 6 : k2 ^= (uint32_t)tail[ 5] << 8; /* fallthrough */
case 5 : k2 ^= (uint32_t)tail[ 4] << 0; /* fallthrough */
k2 *= c2; k2 = util_rotl32(k2, 16); k2 *= c3; h2 ^= k2;
/* fallthrough */
case 4 : k1 ^= (uint32_t)tail[ 3] << 24; /* fallthrough */
case 3 : k1 ^= (uint32_t)tail[ 2] << 16; /* fallthrough */
case 2 : k1 ^= (uint32_t)tail[ 1] << 8; /* fallthrough */
case 1 : k1 ^= (uint32_t)tail[ 0] << 0; /* fallthrough */
k1 *= c1; k1 = util_rotl32(k1, 15); k1 *= c2; h1 ^= k1;
/* fallthrough */
}
}
/* finalization */
h1 ^= size; h2 ^= size; h3 ^= size; h4 ^= size;
h1 += h2; h1 += h3; h1 += h4;
h2 += h1; h3 += h1; h4 += h1;
h1 = fmix32(h1);
h2 = fmix32(h2);
h3 = fmix32(h3);
h4 = fmix32(h4);
h1 += h2; h1 += h3; h1 += h4;
h2 += h1; h3 += h1; h4 += h1;
util_write32(digest + 0, h1);
util_write32(digest + 4, h2);
util_write32(digest + 8, h3);
util_write32(digest + 12, h4);
}

View file

@ -1,303 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2026 Andrea Mazzoleni
/*
* Derivative work of MuseAir v2 in the "long" (len > 32), "b128", and "bfast" configurations.
*
* Note that this specific MuseAir configuration didn't change from v1 to v2.
*
* This implementation also accepts a length <= 32, unlike the original MuseAir,
* which switches to the short version for this length.
*
* https://github.com/eternal-io/museair
*/
/*
* MuseAir v2
* By K--Aethiax
*
* Released into the public domain under the CC0 1.0 license. To view a copy
* of this license, visit: https://creativecommons.org/publicdomain/zero/1.0/
*/
/**
* Analysis of the BFast variant and blinding multiplication
*
* Many fast non-cryptographic hashes (wyhash, rapidhash) use "folding
* multiplication": fold_mul(state ^ input_a, input_b ^ SECRET), where both
* the state and a public constant are XORed directly with input words.
* This is vulnerable to "blinding multiplication": if any operand becomes
* zero, the product is zero, and all accumulated state in that lane is lost.
* An attacker who knows the SECRET constants can trivially craft an input
* word that zeros out an operand, with probability 2^-64 per attempt (or
* 2^-63 considering either operand).
*
* MuseAir BFast avoids this by using a circular accumulator with six
* 64-bit state words. The core loop processes 12 input words per iteration:
*
* state[0] ^= input[0];
* state[1] ^= input[1];
* (lo0, hi0) = wide_mul(state[0], state[1]);
* state[0] = lo5 ^ hi0; // lo5 is from the PREVIOUS step
* ...repeat circularly for state[1] through state[5]...
*
* Inputs are mixed into the state (not XORed with public constants), so
* an attacker must predict the evolving state to craft a blinding input.
*
* Even if a blinding multiplication occurs at the current step (one
* operand is zero, making lo0 = hi0 = 0), the state update becomes:
*
* state[0] = lo5 ^ 0 = lo5
*
* The state is NOT zeroed out: it inherits lo5 from the previous step,
* which still carries entropy from all earlier inputs. The state only
* zeros out if lo5 also happens to be zero.
*
* The probability of lo5 being zero equals the probability that the
* low 64 bits of a 64x64->128 multiplication are zero. This happens
* when the total number of trailing zero bits in both operands is >= 64.
* For uniformly random operands, the exact count of such pairs in
* {0..2^n-1}^2 is (n+2) * 2^(n-1). For n = 64 this gives 33 * 2^64
* pairs out of 2^128 total, so:
*
* P(lo64 = 0) = 33 * 2^-64 ~ 2^-59
*
* The overall probability of a catastrophic state zero-out is therefore:
*
* P(blinding at current step) * P(lo5 = 0)
* ~ 2^-63 * 33 * 2^-64
* = 33 * 2^-127
* ~ 2^-122
*
* This is astronomically unlikely and completely irrelevant for detecting
* silent data corruption, where inputs are real file data (not adversarial).
*
* The "Standard" variant of MuseAir replaces the assignment (=) with a
* subtraction (-=) in the state update, making blinding multiplication
* impossible at a performance cost.
*
* Why BFast was chosen over Standard for SnapRAID
*
* SnapRAID uses the hash exclusively to detect silent data corruption
* (bit rot, firmware bugs, media degradation). The inputs are always
* real file data read from disk, never adversarially crafted content.
* In this context:
*
* - The 2^-122 blinding probability is irrelevant. Random bit errors
* produce uniformly random changes that cannot trigger a blinding
* multiplication. Only a deliberate attacker controlling the exact
* file content could attempt to exploit it.
*
* - Both variants pass all 250 SMHasher3 quality tests and provide
* identical error detection for random corruption.
*
* - BFast is measurably faster, and its structure is more amenable to
* loop unrolling.
*
* The Standard variant's only advantage, full immunity to adversarial
* blinding, provides no benefit when the threat model is physical
* data corruption rather than a malicious actor.
*
* Short-input extension (len <= 32)
*
* The original MuseAir algorithm uses a completely separate "Short"
* hash function for inputs of 32 bytes or less. This implementation
* instead zero-pads short inputs to 32 bytes and processes them
* through the same "Long" code path:
*
* if (len < 32) { memset(buf, 0, 32); memcpy(buf, p, len); }
*
* The motivation is to avoid maintaining two distinct hash algorithms.
* Having a single code path reduces complexity and the potential for
* algorithm defects. Hash functions generally provide a specialized
* short version to improve performance for small keys, but this is
* irrelevant for SnapRAID, which typically hashes 256 KB blocks.
* Short inputs only occur as an exception.
*
* This extension is safe because the original length is mixed into
* the finalization, independent of the zero-padded buffer:
*
* rot = len & 63;
* i = rotl64(i, rot); // left-rotate by original length
* j = rotr64(j, rot); // right-rotate by original length
* k = k - len; // subtract original length
*
* So even though zero-padded buffers for, say, len=1 and len=2 are
* identical, the different rotation amounts and subtraction values
* produce completely different hashes after the final multiplications.
*/
#define u64x(N) (N * 8)
/* AiryAi(0) fractional part calculated by Y-Cruncher */
static const uint64_t MUSEAIR_CONSTANT[13] = {
0x5ae31e589c56e17aULL,
0x96d7bb04e64f6da9ULL,
0x7ab1006b26f9eb64ULL,
0x21233394220b8457ULL,
0x047cb9557c9f3b43ULL,
0xd24f2590c0bcee28ULL,
0x33ea8f71bb6016d8ULL,
0xb5d2697595d0a01fULL,
0x9bb30a32f00e2b4fULL,
0x4acea09317a429d1ULL,
0xc2b2435dfdd545c6ULL,
0xfda811a785572a42ULL,
0xe5f50676bf67137bULL
};
#define mult64_128(l, h, a, b) \
do { \
l = a; \
h = b; \
tommy_mum(&l, &h); \
} while (0)
#define likely(a) tommy_likely(a)
#define unlikely(a) tommy_unlikely(a)
static const uint64_t MASK_I = 01555555555555555555555ULL;
static const uint64_t MASK_J = 01333333333333333333333ULL;
static const uint64_t MASK_K = 00666666666666666666666ULL;
static void MuseAirLoong(const void* bytes, size_t len, const uint8_t* seed, uint8_t* out)
{
const uint8_t* p = bytes;
size_t q = len;
uint8_t buf[32];
if (unlikely(q < 32)) {
memset(buf, 0, 32);
if (q > 0)
memcpy(buf, p, q);
p = buf;
q = 32;
}
uint64_t i, j, k;
uint64_t lo0, lo1, lo2, lo3, lo4, lo5 = MUSEAIR_CONSTANT[6];
uint64_t hi0, hi1, hi2, hi3, hi4, hi5 = MUSEAIR_CONSTANT[6];
uint64_t state[6] = { MUSEAIR_CONSTANT[0], MUSEAIR_CONSTANT[1], MUSEAIR_CONSTANT[2], MUSEAIR_CONSTANT[3], MUSEAIR_CONSTANT[4], MUSEAIR_CONSTANT[5] };
uint64_t seed_a = util_read64(seed);
uint64_t seed_b = util_read64(seed + 8);
state[0] ^= seed_a & MASK_I;
state[1] ^= seed_b & MASK_J;
state[2] ^= seed_a & MASK_K;
state[3] ^= seed_b & MASK_I;
state[4] ^= seed_a & MASK_J;
state[5] ^= seed_b & MASK_K;
if (unlikely(q > u64x(12))) {
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC unroll 2
#elif defined(__clang__)
#pragma unroll 2
#endif
do {
state[0] ^= util_read64(p + u64x(0));
state[1] ^= util_read64(p + u64x(1));
mult64_128(lo0, hi0, state[0], state[1]);
state[0] = lo5 ^ hi0;
state[1] ^= util_read64(p + u64x(2));
state[2] ^= util_read64(p + u64x(3));
mult64_128(lo1, hi1, state[1], state[2]);
state[1] = lo0 ^ hi1;
state[2] ^= util_read64(p + u64x(4));
state[3] ^= util_read64(p + u64x(5));
mult64_128(lo2, hi2, state[2], state[3]);
state[2] = lo1 ^ hi2;
state[3] ^= util_read64(p + u64x(6));
state[4] ^= util_read64(p + u64x(7));
mult64_128(lo3, hi3, state[3], state[4]);
state[3] = lo2 ^ hi3;
state[4] ^= util_read64(p + u64x(8));
state[5] ^= util_read64(p + u64x(9));
mult64_128(lo4, hi4, state[4], state[5]);
state[4] = lo3 ^ hi4;
state[5] ^= util_read64(p + u64x(10));
state[0] ^= util_read64(p + u64x(11));
mult64_128(lo5, hi5, state[5], state[0]);
state[5] = lo4 ^ hi5;
p += u64x(12);
q -= u64x(12);
} while (likely(q > u64x(12)));
state[0] ^= lo5;
}
lo0 = 0, lo1 = 0, lo2 = 0, lo3 = 0;
hi0 = state[1];
hi1 = state[2];
hi2 = state[3];
hi3 = state[4];
if (q > u64x(4)) {
state[0] ^= util_read64(p + u64x(0));
state[1] ^= util_read64(p + u64x(1));
mult64_128(lo0, hi0, state[0], state[1]);
if (q > u64x(6)) {
state[1] ^= util_read64(p + u64x(2));
state[2] ^= util_read64(p + u64x(3));
mult64_128(lo1, hi1, state[1], state[2]);
if (q > u64x(8)) {
state[2] ^= util_read64(p + u64x(4));
state[3] ^= util_read64(p + u64x(5));
mult64_128(lo2, hi2, state[2], state[3]);
if (q > u64x(10)) {
state[3] ^= util_read64(p + u64x(6));
state[4] ^= util_read64(p + u64x(7));
mult64_128(lo3, hi3, state[3], state[4]);
}
}
}
}
state[4] ^= util_read64(p + q - u64x(4));
state[5] ^= util_read64(p + q - u64x(3));
mult64_128(lo4, hi4, state[4], state[5]);
state[5] ^= util_read64(p + q - u64x(2));
state[0] ^= util_read64(p + q - u64x(1));
mult64_128(lo5, hi5, state[5], state[0]);
i = (state[0] - state[1]) ^ MUSEAIR_CONSTANT[7];
j = (state[2] - state[3]) ^ MUSEAIR_CONSTANT[8];
k = (state[4] - state[5]) ^ MUSEAIR_CONSTANT[9];
int rot = len & 63;
i = util_rotl64(i, rot);
j = util_rotr64(j, rot);
k = k - len;
i = i - (lo3 ^ hi3) - (lo4 ^ hi4);
j = j - (lo5 ^ hi5) - (lo0 ^ hi0);
k = k - (lo1 ^ hi1) - (lo2 ^ hi2);
mult64_128(lo0, hi0, i, j);
mult64_128(lo1, hi1, j, k);
mult64_128(lo2, hi2, k, i);
i = lo2 ^ hi0;
j = lo0 ^ hi1;
k = lo1 ^ hi2;
mult64_128(lo3, hi3, i, MUSEAIR_CONSTANT[10]);
mult64_128(lo4, hi4, j, MUSEAIR_CONSTANT[11]);
mult64_128(lo5, hi5, k, MUSEAIR_CONSTANT[12]);
util_write64(out, lo3 ^ hi4 ^ lo5);
util_write64(out + 8, hi3 ^ lo4 ^ hi5);
}

View file

@ -1,264 +0,0 @@
{ "", 0, { 0xec, 0xfa, 0x85, 0x21, 0xca, 0xf3, 0x3e, 0x32, 0x2f, 0x6b, 0xef, 0x39, 0xf7, 0xf2, 0xec, 0x97 }, { 0x26, 0x01, 0xec, 0xe1, 0x83, 0xe8, 0x8c, 0x7b, 0x90, 0x0e, 0x4b, 0xde, 0x01, 0xd5, 0x53, 0xdf } },
{ "a", 1, { 0x0d, 0x7c, 0x23, 0xcf, 0x8f, 0x55, 0xda, 0x27, 0xd0, 0xd9, 0xdb, 0xee, 0x13, 0xbb, 0x6b, 0x1b }, { 0xa4, 0x42, 0x87, 0x4f, 0x88, 0x73, 0x39, 0xd1, 0x41, 0x15, 0xb8, 0x40, 0xa3, 0xb6, 0xc0, 0x5e } },
{ "abc", 3, { 0xbb, 0x15, 0x41, 0x35, 0x28, 0x4c, 0xd0, 0x39, 0x84, 0x53, 0x81, 0x1c, 0x15, 0x8b, 0x6e, 0x6d }, { 0x18, 0xe4, 0x38, 0x31, 0x15, 0x50, 0xbc, 0x1b, 0xe3, 0x67, 0x76, 0x94, 0xf1, 0xcf, 0x38, 0xf4 } },
{ "message digest", 14, { 0x68, 0xe0, 0x5a, 0xa3, 0x01, 0x72, 0x29, 0x26, 0x33, 0x7f, 0x2b, 0x67, 0x3a, 0x72, 0x76, 0x0c }, { 0x51, 0xa0, 0xc8, 0x1e, 0x0a, 0x47, 0xc0, 0xa7, 0xc7, 0x7f, 0x21, 0x05, 0x9a, 0x5c, 0x92, 0x33 } },
{ "abcdefghijklmnopqrstuvwxyz", 26, { 0x54, 0x2f, 0xcb, 0x3d, 0x70, 0x47, 0x1d, 0x55, 0x9c, 0x1d, 0x5c, 0x53, 0x79, 0x5f, 0x25, 0x01 }, { 0xac, 0x4f, 0x52, 0x96, 0x83, 0x93, 0xd6, 0xa1, 0x38, 0x4a, 0x8f, 0xc9, 0xdf, 0xf8, 0xe0, 0x57 } },
{ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 62, { 0xb2, 0xbf, 0x48, 0x8c, 0x78, 0xe7, 0xbd, 0x27, 0xcd, 0xe2, 0x5d, 0x18, 0xfd, 0x72, 0xab, 0xed }, { 0xe3, 0x64, 0x46, 0x3d, 0xc4, 0x81, 0xdf, 0x27, 0x74, 0x39, 0xd4, 0x92, 0x49, 0x81, 0x3a, 0x0f } },
{ "The quick brown fox jumps over the lazy dog", 43, { 0xd6, 0xa7, 0x07, 0xdd, 0xdb, 0x3d, 0x21, 0x88, 0x04, 0x85, 0x11, 0x5e, 0x5c, 0x59, 0x4a, 0xbd }, { 0x5f, 0x75, 0xc0, 0x9c, 0x71, 0xd2, 0xb1, 0x4a, 0x2e, 0x7a, 0x0f, 0xfb, 0x64, 0xe4, 0xdc, 0xce } },
{ "\xf6", 1, { 0x29, 0xb0, 0x72, 0x21, 0x14, 0x86, 0x11, 0xab, 0x90, 0xeb, 0x0f, 0x32, 0xb8, 0x90, 0x4e, 0x17 }, { 0xf4, 0x39, 0x01, 0xc9, 0x5e, 0xe2, 0xcb, 0xd8, 0x0e, 0xb1, 0xa9, 0x1d, 0x8e, 0x39, 0xcf, 0x8a } },
{ "\xf7\x39", 2, { 0xef, 0x01, 0x35, 0x91, 0xd9, 0x27, 0x0a, 0x16, 0x47, 0x28, 0x0d, 0x34, 0x30, 0x2f, 0xdf, 0x31 }, { 0x8c, 0xe1, 0x8c, 0x35, 0xdc, 0xc3, 0x3a, 0x1e, 0x9c, 0x9b, 0x89, 0x4c, 0x0a, 0x4a, 0x8b, 0xbb } },
{ "\xcb\x8d\xab", 3, { 0x19, 0x93, 0x81, 0xe2, 0x3d, 0xf8, 0xa8, 0x16, 0x80, 0x61, 0x66, 0xd7, 0xb5, 0xa9, 0xc3, 0x3e }, { 0x5a, 0xc0, 0xf8, 0x41, 0x14, 0x15, 0x00, 0xdc, 0x49, 0x25, 0xa0, 0x7d, 0xe6, 0xef, 0x07, 0x5e } },
{ "\x2f\xdc\x11\x68", 4, { 0x96, 0xb4, 0x38, 0x50, 0x50, 0x02, 0x32, 0x02, 0x5c, 0xfb, 0x45, 0x33, 0x09, 0x45, 0xa7, 0x36 }, { 0x86, 0x53, 0x98, 0xe4, 0x51, 0x3b, 0xba, 0x51, 0x31, 0x3d, 0x0c, 0xb5, 0x57, 0x40, 0x42, 0xbf } },
{ "\x24\x74\x31\x0e\xc8", 5, { 0x24, 0xe1, 0x46, 0xda, 0x59, 0x78, 0x43, 0x3a, 0x41, 0xa9, 0x7b, 0xe4, 0x88, 0x66, 0xb8, 0x92 }, { 0x74, 0x4f, 0xf3, 0x03, 0x7a, 0x61, 0xaa, 0x0b, 0xb7, 0xd6, 0xe6, 0x4b, 0x25, 0x6e, 0xab, 0x00 } },
{ "\x58\x10\x5e\xd4\xa1\x34", 6, { 0xb9, 0xc6, 0xac, 0x3f, 0x30, 0xf1, 0xde, 0x94, 0x39, 0xe4, 0xbf, 0xa3, 0xbd, 0x96, 0x28, 0xf6 }, { 0xff, 0x9b, 0x58, 0xe6, 0xea, 0x68, 0x5d, 0x1d, 0xf3, 0x74, 0x23, 0x59, 0x00, 0x29, 0x6c, 0x39 } },
{ "\xc8\x87\x61\x1d\xb9\x21\x56", 7, { 0x7c, 0x19, 0xef, 0xa0, 0xb8, 0x0e, 0xec, 0xc8, 0x83, 0xce, 0x49, 0x23, 0x7a, 0x7d, 0xf8, 0x25 }, { 0x46, 0x8d, 0xa7, 0x10, 0x69, 0xef, 0x94, 0x27, 0xff, 0xd7, 0x5d, 0x0b, 0xf1, 0x74, 0x39, 0xed } },
{ "\x0b\x41\x36\xa3\x7d\x24\x35\xcc", 8, { 0x4b, 0xeb, 0x90, 0xc6, 0x67, 0x1d, 0xbf, 0x3b, 0x32, 0x5b, 0x29, 0x51, 0x2e, 0xb4, 0x7d, 0xbe }, { 0x17, 0xc3, 0x7e, 0x4f, 0x38, 0xe7, 0x34, 0xcc, 0x88, 0x0c, 0x1f, 0xd1, 0x50, 0x1a, 0xd3, 0xba } },
{ "\x7a\xe3\xa3\x36\x00\x75\x9c\x46\x5b", 9, { 0x7f, 0x76, 0x62, 0x13, 0x8a, 0xdc, 0xc1, 0x99, 0x75, 0xe5, 0x08, 0xbc, 0x44, 0x73, 0x1a, 0x9e }, { 0x8e, 0x4a, 0xc8, 0x25, 0xff, 0x6e, 0x50, 0x51, 0xa3, 0xa2, 0x7b, 0x51, 0x7f, 0x68, 0xd1, 0x2f } },
{ "\x3d\xcb\x2b\x3f\x15\x36\x3c\xf9\xa6\xa2", 10, { 0x71, 0x0a, 0x20, 0x33, 0x0a, 0xa8, 0x28, 0x1d, 0xb3, 0xa0, 0xb3, 0xa2, 0x93, 0x10, 0xac, 0xa0 }, { 0xa7, 0xb5, 0x82, 0x54, 0x46, 0xc9, 0xa7, 0x9b, 0x3d, 0x3d, 0x87, 0xc0, 0x42, 0xee, 0xbd, 0xc5 } },
{ "\xf9\x8a\x69\x67\x5e\xd1\xd2\xfd\xf4\xf1\xb2", 11, { 0x60, 0xc3, 0x01, 0x6b, 0x4c, 0x1b, 0xd6, 0xc6, 0x14, 0x3a, 0xb5, 0x52, 0x05, 0x1c, 0x8a, 0x6a }, { 0xba, 0x2e, 0x77, 0x20, 0x41, 0xfa, 0xec, 0x94, 0x11, 0x30, 0x8c, 0xde, 0x24, 0x8a, 0xce, 0x5c } },
{ "\xfe\x93\x54\x96\xc6\xac\x7d\xf2\x89\x78\x0c\x50", 12, { 0x8f, 0x48, 0x65, 0x7d, 0x1c, 0xa2, 0x57, 0xc6, 0x89, 0xa2, 0x9b, 0x1e, 0xc0, 0x77, 0xff, 0x37 }, { 0x21, 0x15, 0x58, 0x62, 0xf0, 0x3e, 0x9b, 0x78, 0xb4, 0xa5, 0xb4, 0xdd, 0xcb, 0xe5, 0xcf, 0x5d } },
{ "\x04\xa5\x95\xfa\xdf\x0c\x14\xdc\x4f\x78\x53\xb7\xed", 13, { 0x20, 0xa4, 0xd1, 0xca, 0xf0, 0xc8, 0x8a, 0x4f, 0x0b, 0xe0, 0xb6, 0xc3, 0xcc, 0x92, 0x4b, 0x51 }, { 0x63, 0xcf, 0xfd, 0x23, 0xa0, 0x54, 0xdb, 0xad, 0xda, 0x1f, 0xa5, 0x52, 0x7e, 0xe8, 0xf5, 0x8d } },
{ "\x26\x31\x16\x02\x8b\x06\x95\x38\xf7\x44\xe1\xca\x79\x83", 14, { 0xba, 0x70, 0x56, 0x4a, 0x10, 0x0f, 0x98, 0x8a, 0x16, 0xd9, 0xd7, 0xb3, 0x55, 0x19, 0x4f, 0x60 }, { 0x01, 0x5b, 0x00, 0xbd, 0xcb, 0xb9, 0xbb, 0x1c, 0x33, 0x29, 0x93, 0x96, 0x9a, 0xb5, 0x3b, 0xd3 } },
{ "\xe5\x08\x53\xbd\xff\x4d\xe9\xb8\xe3\x53\xfc\xa4\xe3\xfc\x46", 15, { 0xed, 0x05, 0x22, 0x0d, 0xa5, 0x62, 0x0b, 0x36, 0x9f, 0xbe, 0xcd, 0xb0, 0xf0, 0x2a, 0x51, 0x48 }, { 0x6f, 0xe8, 0xc9, 0x89, 0xbc, 0x9e, 0xd1, 0x35, 0xd8, 0x4d, 0xbd, 0xa7, 0xcb, 0xff, 0xd7, 0x46 } },
{ "\x6d\x9a\x82\xa2\x16\x93\xc8\xfa\xe2\x52\xeb\x60\x57\x74\xba\x91", 16, { 0x48, 0x0d, 0xfa, 0x3d, 0x2b, 0x73, 0xb9, 0xbf, 0x1b, 0x7d, 0x4c, 0x38, 0x96, 0x47, 0x21, 0xac }, { 0x4f, 0x69, 0xb8, 0xf1, 0xb1, 0x99, 0xe3, 0xc6, 0x18, 0x24, 0x66, 0x20, 0xeb, 0xcb, 0x74, 0x94 } },
{ "\x64\x7b\x6c\xf4\x87\xb0\x4c\x33\xda\xbb\x27\x3a\x6a\xfd\x25\x37\x2e", 17, { 0xd7, 0xb5, 0x6e, 0x31, 0xfe, 0x97, 0x9d, 0x04, 0x4f, 0xb3, 0x07, 0x53, 0x58, 0x4c, 0x6d, 0x92 }, { 0xe1, 0xfd, 0xc5, 0x7f, 0x54, 0xdb, 0x4e, 0x77, 0x01, 0x6f, 0xed, 0xce, 0xcc, 0xe6, 0x3b, 0x57 } },
{ "\xe4\xff\x50\x32\xb1\x59\xa5\xba\x7a\xa6\x4d\x38\x05\x14\x4b\x77\xab\x43", 18, { 0x97, 0x5f, 0xe5, 0xa6, 0x78, 0xf0, 0x3e, 0xb6, 0x48, 0xa5, 0x53, 0x89, 0x9a, 0x53, 0x3a, 0x6d }, { 0x81, 0xe4, 0xe5, 0x54, 0x3f, 0xf5, 0x47, 0xf0, 0xe4, 0x91, 0xa2, 0xf7, 0x41, 0xf6, 0x47, 0xa1 } },
{ "\x0b\xf2\xf4\x0b\x2c\x8c\x9f\xdd\xfd\x81\x39\xba\x10\x75\x14\x14\x10\xd9\xe4", 19, { 0xc6, 0x69, 0xbe, 0xe2, 0xf8, 0xc3, 0xe9, 0x68, 0x3b, 0x68, 0x7d, 0x93, 0x71, 0xeb, 0x13, 0xdf }, { 0xc4, 0x3f, 0x24, 0x8d, 0x7b, 0x22, 0x9f, 0x31, 0x92, 0xd7, 0x12, 0x3f, 0x70, 0x04, 0x2d, 0xbb } },
{ "\xdf\xad\xe3\x3c\xe6\x11\xc4\xaf\x4e\x4d\xbb\x19\x2e\xc8\x87\x8d\x86\xbf\xae\xf8", 20, { 0xe7, 0x0a, 0x75, 0xf0, 0x45, 0x24, 0x13, 0x5c, 0xa5, 0x40, 0xae, 0x1c, 0xf2, 0xaf, 0xf7, 0x2e }, { 0x9e, 0xc6, 0x5f, 0x3f, 0xd1, 0x71, 0xda, 0xae, 0xcf, 0xdb, 0xa7, 0x7b, 0x48, 0xd2, 0xe2, 0x26 } },
{ "\xc3\x06\x1f\x5a\x4c\x3c\xa3\xf5\xc5\x2d\xcb\x3e\xcf\xf0\x37\x94\x89\x58\x37\xbc\x81", 21, { 0x3f, 0x8e, 0xf8, 0x60, 0xd0, 0x53, 0x5d, 0x1d, 0x90, 0x96, 0x22, 0xca, 0x32, 0x98, 0x02, 0x3c }, { 0x2d, 0x22, 0xec, 0x95, 0xc7, 0x50, 0xee, 0x7e, 0x48, 0x88, 0xd4, 0x12, 0xfc, 0xa5, 0x11, 0x18 } },
{ "\x06\xd9\x36\x42\x30\xec\x87\x20\xb0\x3c\xd8\x3c\x42\xd3\x99\x1e\xd1\xc8\x63\x8e\xdb\xa9", 22, { 0xc7, 0x3d, 0xa2, 0x80, 0x23, 0xdd, 0xd5, 0xc4, 0x51, 0xb0, 0xe3, 0x79, 0x4b, 0x23, 0xd8, 0xb2 }, { 0xe9, 0x89, 0x45, 0x85, 0x0c, 0x8e, 0xb6, 0x8e, 0x97, 0xbb, 0xb5, 0xa3, 0x76, 0x40, 0xa2, 0x53 } },
{ "\x50\x5c\x22\x5c\xa5\xf3\xf9\xe7\x17\xcd\x71\x9f\xf1\x5b\xa4\xa4\xf2\xe5\x37\xf5\x9e\xed\xb5", 23, { 0xdb, 0xd0, 0x77, 0x23, 0xe3, 0xc0, 0x96, 0x5b, 0x78, 0x5e, 0xcb, 0x03, 0x56, 0xda, 0xf2, 0x04 }, { 0x09, 0x59, 0x30, 0xdb, 0x7b, 0x67, 0xae, 0x75, 0xb5, 0x45, 0x52, 0x7f, 0x6f, 0xca, 0x6c, 0x4f } },
{ "\xbb\xde\x88\x01\x7c\x1f\x45\x38\x97\x4c\xa8\x55\x97\x92\xdd\x32\x42\xc4\xa3\x90\x9a\xf1\xe9\x51", 24, { 0x55, 0xec, 0x36, 0x76, 0xa8, 0xed, 0x68, 0xf6, 0x48, 0xa8, 0x0c, 0x1d, 0x37, 0x7b, 0x43, 0x34 }, { 0xc7, 0x2f, 0x2d, 0x75, 0x71, 0xe7, 0xc2, 0x12, 0x97, 0x78, 0x88, 0x42, 0x7f, 0x87, 0x1f, 0x2f } },
{ "\x0f\x15\xbd\x39\xb2\x07\x94\xde\xe1\x25\x76\x96\x23\x94\x1e\x68\x66\x61\x81\xca\x5c\xe8\x73\x88\x94", 25, { 0x71, 0xda, 0x33, 0x84, 0x68, 0x92, 0xdf, 0xf5, 0x28, 0xb2, 0x36, 0xd2, 0x32, 0xba, 0x0c, 0xaf }, { 0x3d, 0xf3, 0xba, 0xaf, 0x62, 0x79, 0xaa, 0x31, 0x60, 0xb4, 0xb8, 0xda, 0x8d, 0x6f, 0x4e, 0x14 } },
{ "\x4b\x26\x61\x0f\xfc\x64\xdc\x8c\x8d\x3b\x5b\x85\x44\xeb\xb1\x0a\x73\x59\x81\x11\x62\x65\x4d\xcf\x98\xf9", 26, { 0x77, 0xb9, 0x88, 0x2d, 0xa4, 0x26, 0xfb, 0xd6, 0x1e, 0x8e, 0x4a, 0x7f, 0x33, 0x2f, 0x67, 0x2d }, { 0x08, 0xd6, 0xec, 0x18, 0x36, 0x79, 0x76, 0x28, 0xa0, 0x24, 0x14, 0x6c, 0xa0, 0x04, 0x26, 0x8e } },
{ "\x0c\x16\x38\x42\x1c\x04\xc3\x72\xa9\x42\xf2\xf6\x79\x96\xe6\x41\xcd\xbb\x2a\x3e\x11\x20\xba\xc3\x45\xa9\xf9", 27, { 0xa7, 0xe0, 0x52, 0xdb, 0xd7, 0xbf, 0xe3, 0x68, 0xb9, 0x41, 0xc6, 0x1e, 0x5a, 0xf5, 0xef, 0xa9 }, { 0xf7, 0xba, 0xbd, 0x21, 0xb3, 0xd7, 0xa2, 0xe0, 0xc4, 0x18, 0xf6, 0xca, 0xfd, 0x1b, 0xa2, 0x74 } },
{ "\x6e\x7f\x2a\xe4\x9d\xb7\xfc\x8f\x10\x45\xe5\xc9\x1f\x45\x7a\x03\xfc\x13\xda\xd9\x92\xb1\xf1\x74\xcc\x21\xe5\x1b", 28, { 0x3b, 0xb2, 0x8f, 0x5e, 0x71, 0x01, 0x54, 0xb3, 0x1f, 0xe0, 0x98, 0x62, 0xc2, 0x75, 0x7b, 0x64 }, { 0x86, 0x40, 0x7f, 0x18, 0x46, 0x9f, 0xc1, 0x52, 0x4c, 0xc9, 0x42, 0xf5, 0xa2, 0x8e, 0x9f, 0xfb } },
{ "\x3e\xe4\x33\x05\x1a\x38\x1d\xd4\x77\xcc\x58\xd9\xf6\x10\x0d\x17\x12\x3f\x41\x75\xc9\xac\x72\x18\x29\x8b\xa1\xd0\x33", 29, { 0x70, 0x31, 0xa9, 0x05, 0x95, 0x13, 0x28, 0xe0, 0x10, 0x5d, 0x13, 0x85, 0xad, 0xab, 0x46, 0x8b }, { 0x29, 0xa1, 0xc4, 0x5d, 0xcc, 0x9a, 0xa9, 0x71, 0x11, 0x80, 0x91, 0x86, 0xd2, 0x8d, 0xd3, 0xa7 } },
{ "\xd9\x11\x4a\x2d\xc7\x6d\x35\x49\xfb\x0d\x1a\x66\x10\x16\x27\xe6\x8f\x2f\x80\x7d\x41\x05\xed\x07\xec\x64\xf7\x53\x09\x8c", 30, { 0x3c, 0xff, 0xb3, 0x4c, 0xbc, 0xab, 0x47, 0xbd, 0xb8, 0x59, 0xe0, 0x5e, 0x05, 0x4b, 0xe9, 0x7a }, { 0x57, 0xf4, 0xbf, 0x66, 0xd5, 0xb7, 0x49, 0xb7, 0xf1, 0x33, 0x97, 0xe2, 0x0c, 0x91, 0x06, 0x82 } },
{ "\xe9\x15\x3f\x2c\x13\xe0\x01\x26\x2d\x84\xc3\x1f\x4a\x77\xba\x38\x65\x3d\x37\x4a\xf8\x76\xec\xf6\x6a\x66\x51\x09\xd4\xf5\x6a", 31, { 0xbd, 0x6c, 0xe9, 0x1f, 0x86, 0xb1, 0x1f, 0x6b, 0x6c, 0x7e, 0x4f, 0x61, 0x1e, 0x58, 0xaf, 0x8a }, { 0xad, 0x36, 0x03, 0xef, 0x63, 0xcd, 0xae, 0x30, 0xba, 0x8d, 0x49, 0x3e, 0x2e, 0x13, 0x43, 0x0b } },
{ "\x0a\x9c\xa6\x92\xf6\x91\x5d\xb3\xda\xcc\x56\xbe\xdc\x8c\xa7\xdf\x23\x79\x06\x15\xe7\x55\x97\x77\xf9\x79\x3c\xc9\x74\xc3\x01\x72", 32, { 0x44, 0x54, 0x33, 0x3d, 0xa0, 0x33, 0x07, 0xb4, 0xd2, 0x21, 0xd9, 0x38, 0x11, 0x44, 0x2e, 0x0a }, { 0x22, 0xd9, 0xc2, 0x47, 0x80, 0xea, 0x68, 0xdd, 0x50, 0x69, 0x88, 0x30, 0xe8, 0x1c, 0xa4, 0x4e } },
{ "\xd5\x1c\x43\x5d\x86\x79\xe3\x06\x19\x43\x86\xd0\xd3\x73\x1e\xcb\x6f\x08\x89\x6c\x53\xde\x5f\x9d\x25\x6b\x6f\x98\xd4\x3c\x6e\x64\x5c", 33, { 0x8e, 0x5e, 0x2d, 0xf4, 0x90, 0xd3, 0x60, 0x82, 0xf2, 0x65, 0x02, 0x8b, 0xa2, 0x1d, 0x2c, 0xb2 }, { 0x3b, 0x33, 0xca, 0x63, 0x52, 0x33, 0xc4, 0x37, 0x3b, 0xc5, 0x0d, 0x90, 0x44, 0xb2, 0xf1, 0xba } },
{ "\x1a\xcf\xd3\x03\xf9\x19\x12\x56\xb1\x21\xe6\xd2\x7e\x30\xee\x42\x96\x3a\xee\x9f\xdf\x92\x66\xbe\x78\xc3\x88\x37\xf4\x6a\x4b\xe8\x77\x55", 34, { 0x96, 0xa5, 0xe7, 0x7e, 0x42, 0x64, 0x30, 0x10, 0x1f, 0xaa, 0xf6, 0x96, 0xa0, 0xaa, 0x9b, 0xdd }, { 0x64, 0xb3, 0x68, 0xfa, 0x26, 0xf2, 0xcf, 0x11, 0x61, 0x0b, 0xaf, 0xc9, 0xa3, 0x98, 0x6d, 0xd6 } },
{ "\x2d\x16\x9e\x50\x6a\x7e\x6a\xe9\xd3\x02\x29\xac\x86\x34\x83\x3b\xe6\x83\xb1\x55\xa0\xcb\x17\xa4\xbf\xfe\xaf\x73\x00\xd1\x6f\x7e\x43\xa5\xe3", 35, { 0x49, 0x10, 0xf7, 0x34, 0x18, 0x61, 0x5c, 0x58, 0xb4, 0xe5, 0xa9, 0xa3, 0x76, 0x7d, 0x97, 0xf0 }, { 0xfa, 0x57, 0xac, 0x87, 0x27, 0x69, 0x0c, 0xc3, 0x6c, 0x3e, 0x08, 0x86, 0x2c, 0xd5, 0x7c, 0x40 } },
{ "\x88\x7b\x06\x1f\xa0\x8b\xf8\xd0\x7d\xe8\xde\x59\x81\xe2\x5b\x22\x23\xe2\x43\xbd\xaf\x2f\x79\x54\xa8\xb4\xa9\x17\x11\x42\x67\x7a\xe5\x86\xae\x5f", 36, { 0xd8, 0x72, 0xe2, 0x54, 0x9a, 0x09, 0x7d, 0x59, 0xd2, 0x36, 0xee, 0x18, 0xab, 0x29, 0x32, 0x05 }, { 0xb7, 0x5c, 0x04, 0x90, 0xd6, 0x32, 0x94, 0xd9, 0x8d, 0xbc, 0x89, 0x5d, 0xe2, 0x56, 0x8a, 0x6e } },
{ "\x66\x07\x0c\xca\xf7\xf8\xa4\x53\x8a\x4d\x74\x28\x42\x6c\xf0\x98\x4b\xce\xa8\x54\xbb\x63\xfb\x8f\x88\x07\x7f\xe1\x36\xcc\xbf\x12\x19\xda\xbb\x27\xb5", 37, { 0xe7, 0x4e, 0x2b, 0xad, 0xc7, 0x80, 0x25, 0x15, 0xc3, 0x56, 0x84, 0x4c, 0x81, 0x61, 0x0e, 0x1b }, { 0xaf, 0x2e, 0x53, 0xd7, 0x15, 0xc8, 0xfa, 0xe2, 0x4d, 0x70, 0xc7, 0xd5, 0xe2, 0x6b, 0x84, 0x71 } },
{ "\xf5\xab\x1e\x7e\xc5\xe6\x5e\xc1\x16\xde\x11\x50\x68\x4c\x44\xf8\x87\x9d\x6c\xf7\x2c\x57\x73\x46\x82\xde\x3d\xa6\x65\x37\xc0\x83\x8f\xc5\x5d\xa4\x43\x4f", 38, { 0x80, 0xea, 0x33, 0x16, 0xca, 0x01, 0x79, 0xed, 0x1f, 0x21, 0x45, 0xcc, 0xcb, 0xa5, 0x88, 0xbf }, { 0x3c, 0x60, 0xbf, 0xff, 0xc1, 0xb9, 0x90, 0x34, 0xf5, 0xa6, 0xec, 0x78, 0xe7, 0x85, 0x11, 0xf0 } },
{ "\x70\x03\x1d\xc3\x6d\xfd\xba\xa4\x18\xac\x95\x41\x59\xb1\xb7\xf4\x12\x32\x96\x1a\x47\xe3\x5a\x27\x38\xee\x3e\xff\x3f\xc2\xb8\x2a\x30\xc2\xe2\xec\xf1\x56\x0e", 39, { 0x73, 0x3e, 0x45, 0xc4, 0x83, 0x06, 0xab, 0x3e, 0xf3, 0x51, 0xf5, 0x9b, 0xc1, 0xda, 0x05, 0x28 }, { 0xd8, 0x02, 0x1a, 0x02, 0xc7, 0xb9, 0x9e, 0x09, 0x30, 0x07, 0x7c, 0xa8, 0xa0, 0x55, 0xe0, 0x6a } },
{ "\x36\x45\xac\x62\x13\x74\x11\x57\x3c\x5d\x94\x8e\x36\x3b\x77\xc3\xbb\x83\xe1\xc3\x35\x07\x6b\x49\xd5\x60\x01\xae\xbc\x06\x5d\xa1\x19\x0e\x89\xf2\x7d\x2b\xb3\xf9", 40, { 0xfa, 0xf8, 0x36, 0xc1, 0xe2, 0xa7, 0x6d, 0xf8, 0xc9, 0xee, 0x66, 0x92, 0xaf, 0x8a, 0x7c, 0xcb }, { 0x23, 0x30, 0x1f, 0x97, 0x8f, 0xae, 0xd3, 0x63, 0x89, 0xf2, 0x6c, 0xd0, 0xab, 0x48, 0x2c, 0x3e } },
{ "\x13\xc5\xf7\x9a\xe0\x63\x68\xd6\x8a\x54\x51\x12\x33\xe8\xc4\x36\x1e\xbb\xd6\xc6\x61\x16\x4e\x65\x36\xea\x16\x92\x89\x28\xf8\xbb\x8f\xdb\xc3\xe4\x7d\x57\x70\xc3\x1c", 41, { 0xea, 0x52, 0x2d, 0xf0, 0x1b, 0x50, 0x77, 0xe4, 0x58, 0xef, 0x1c, 0x4f, 0x35, 0x40, 0x30, 0x41 }, { 0xc9, 0xd5, 0x7a, 0x06, 0x3a, 0x78, 0xc9, 0x84, 0x32, 0x7e, 0xbb, 0x86, 0x22, 0xc9, 0x6c, 0x4b } },
{ "\xab\xf2\x9e\x4e\x07\xb9\x6c\xed\xd7\x03\xc7\xe7\x02\x17\xaa\x9d\x37\x5b\x0e\x3d\x4b\x1d\x2a\x83\xc3\xec\xe3\x0c\x7b\xc6\xae\x86\x93\x29\xc2\xdf\xa7\x48\x96\xd2\xbb\x30", 42, { 0x8d, 0xea, 0xa5, 0x27, 0xba, 0xba, 0xaf, 0xb0, 0xe9, 0x67, 0x0d, 0xab, 0x71, 0xf5, 0x69, 0x4c }, { 0xfd, 0x02, 0xde, 0xf6, 0x20, 0xa2, 0x32, 0x3c, 0xe5, 0x44, 0x2e, 0x19, 0x7b, 0xd5, 0x24, 0x77 } },
{ "\xda\x29\x6d\x50\xea\x83\xa5\x57\xb2\xfe\xe5\x2b\x1a\xd1\xd9\xdc\xcf\xef\x7d\x1a\x8c\xa6\xc6\x83\x86\x1a\xbd\xc7\x3c\xe2\x5d\xd2\x0b\xf0\x1a\xcd\x07\x5a\x77\xeb\x2c\x66\xe8", 43, { 0x1f, 0x63, 0x17, 0xad, 0x10, 0x1c, 0x75, 0x8f, 0xfd, 0xf4, 0x7a, 0x74, 0x1e, 0x9e, 0x3c, 0xa7 }, { 0x16, 0x0e, 0xe8, 0x32, 0x18, 0x78, 0x20, 0x42, 0x61, 0xfd, 0x75, 0x41, 0x4c, 0xc6, 0x3b, 0x16 } },
{ "\xa6\x8a\xe5\x31\xfe\x40\xaa\xa4\x9c\x8c\x31\xba\x85\x44\x5e\x7c\x0a\xb5\x6b\x6b\x1c\xcc\x61\x9f\xe8\x42\x2b\xaa\x55\x1e\x7d\xe5\xfb\xb5\x39\x30\x46\x97\x11\xe9\xd7\xaf\xbc\xa5", 44, { 0x4d, 0x20, 0x76, 0xd5, 0x43, 0x9b, 0xf4, 0x50, 0x5a, 0x75, 0x13, 0xa3, 0x05, 0xd0, 0xf2, 0xff }, { 0xe0, 0xb4, 0xb3, 0xfd, 0x6e, 0x51, 0x0d, 0x94, 0xc3, 0xbc, 0xe9, 0x25, 0x58, 0xf5, 0x60, 0xdd } },
{ "\x24\x57\xba\xb9\xe4\x43\x9e\xf3\x67\x60\xb4\x48\xbb\x0a\x6a\x60\xde\xc4\x1e\x95\x2d\xcf\x96\x83\xa3\xe5\x66\x5d\xe3\x65\x28\x4a\x40\x1d\x77\xf5\xf9\x3a\xd6\xcd\x97\x9d\x7e\xb4\x66", 45, { 0xa1, 0xc2, 0x91, 0xa0, 0x8f, 0xd6, 0x0f, 0x1c, 0xe3, 0x42, 0xe4, 0x4f, 0x68, 0xf3, 0xc0, 0x12 }, { 0x14, 0xcd, 0x6d, 0x7f, 0x36, 0x32, 0x30, 0x88, 0x20, 0x34, 0xe9, 0xb0, 0x16, 0xce, 0x72, 0x60 } },
{ "\x34\x67\xf0\x23\xd3\x9a\x54\x60\x05\x2f\x12\xac\xa0\x64\xd1\x5b\x8e\x09\xe7\x1c\xc4\x64\x23\xfe\x98\x74\xad\x90\xd4\xc4\x18\xcf\x33\xba\x6d\x2e\xef\x7d\x12\xe0\x22\x1f\x46\x81\xde\x84", 46, { 0x5e, 0x14, 0xbb, 0x6d, 0xb5, 0x01, 0xab, 0x23, 0xf3, 0x61, 0x02, 0xb3, 0x66, 0xd5, 0x7d, 0xc2 }, { 0x97, 0x66, 0x0c, 0x59, 0xe5, 0x92, 0x35, 0xba, 0x9c, 0x8f, 0x0e, 0x72, 0x67, 0x7a, 0x41, 0x71 } },
{ "\xd0\x58\x9c\x72\xe2\x15\x46\x48\x53\xba\x85\xd6\xed\x01\x84\x87\xfa\xf9\xba\x89\x26\x48\xcd\x65\x3f\x1e\x28\x3b\xbf\xb9\xf8\x6d\xd0\x97\x67\x24\xab\x3b\x8e\xdc\x2c\x7c\x2a\x05\xb1\xd9\xfc", 47, { 0x3a, 0x9c, 0x29, 0x83, 0xb4, 0x51, 0x6a, 0x60, 0xf7, 0x6c, 0x79, 0x6a, 0x62, 0x09, 0x6b, 0xb3 }, { 0xb1, 0x5c, 0xc8, 0xb0, 0x4e, 0xf6, 0xc0, 0x09, 0x49, 0x85, 0x94, 0x29, 0x11, 0x6a, 0x6f, 0x18 } },
{ "\x69\x7b\x92\xda\x71\xb6\x8a\x09\xe4\xf8\x62\x34\x7f\x40\x52\xf3\x11\x93\x70\x4a\xf2\x50\x86\x88\x5e\x05\xe8\xce\x9f\xc6\x26\x7d\xcd\x31\x1e\xd2\x60\x3c\xa8\x03\x46\xfc\x47\xb3\x8c\x4a\x52\xa9", 48, { 0xe8, 0x05, 0x2b, 0x08, 0x71, 0xad, 0xe4, 0x28, 0xfb, 0x79, 0xe6, 0x74, 0x1c, 0x55, 0x98, 0xf5 }, { 0x35, 0x4a, 0x4f, 0xbf, 0x47, 0xaa, 0x32, 0x65, 0x6e, 0x14, 0xeb, 0x3a, 0x97, 0x45, 0x47, 0xd4 } },
{ "\x8e\xa3\x40\xed\x7a\x29\x3c\x6a\x6f\x1c\xa4\xd1\x29\xbd\x8a\xb7\xf7\x70\xa7\xea\x4f\x02\xce\xd1\x71\xa1\x97\xa4\x20\x98\xc2\xbe\xf0\x85\xc4\xc0\x93\x93\x34\x8c\xfa\x1a\xcf\x5b\xd6\x02\x4d\xe0\x8f", 49, { 0x15, 0x02, 0xb4, 0x26, 0x0d, 0x05, 0x9d, 0xdf, 0x5c, 0xc7, 0xcf, 0x4c, 0x54, 0x8b, 0x0b, 0x1d }, { 0x44, 0xee, 0x56, 0x30, 0x13, 0xb6, 0xe0, 0xa7, 0x35, 0x93, 0x78, 0xeb, 0x07, 0x28, 0x44, 0xbe } },
{ "\xfa\x1e\xf0\xce\x8a\x22\x3e\xec\x7d\x65\xe3\xd5\xc5\x3e\x85\x3b\xbe\x35\xed\x84\xfc\x31\x31\x9b\x50\xc5\xe6\x24\xff\xd4\xc6\xa6\x63\x41\xe8\xcf\x79\xa0\xf3\x12\x93\x68\x62\xb4\x2a\x08\x07\x05\x01\x13", 50, { 0x8a, 0xaa, 0x3f, 0x7a, 0x88, 0x70, 0xc9, 0x8a, 0x4c, 0x0e, 0x95, 0x19, 0xe1, 0x6e, 0x4d, 0x0e }, { 0xb1, 0xec, 0x55, 0x40, 0x04, 0xf8, 0x32, 0xd4, 0x4b, 0x51, 0xa9, 0xa1, 0x4c, 0xd3, 0xda, 0x55 } },
{ "\x0b\xaa\xe5\xba\x0d\x5f\x6b\xd0\xf5\xd5\xe4\x99\x26\xb5\x76\x08\xa9\x2c\x1d\x08\x43\xbd\x9d\x81\x31\x29\xc0\x03\x12\x0c\x0a\x4e\xba\x5a\xfb\x26\xe3\xde\xad\x6b\x36\x26\xf4\xd5\x09\x64\xe1\x55\x28\xea\x1f", 51, { 0x0a, 0xfe, 0xfb, 0xc7, 0x25, 0x4b, 0xc3, 0xd0, 0x61, 0x1a, 0xbf, 0xbc, 0x12, 0x50, 0x9f, 0xb7 }, { 0xd8, 0x0a, 0x6a, 0xf1, 0x04, 0xce, 0xc8, 0x7e, 0x94, 0x40, 0x39, 0x5f, 0x8e, 0x13, 0xd7, 0x1a } },
{ "\xb8\x70\xb8\x5a\x7a\x4e\x90\xe4\xd5\xef\x2d\xf7\x4c\x77\x02\xb9\xf0\x96\x80\x78\xa7\xc7\x51\xe6\x34\x6b\x00\x2d\x1f\x38\x16\xe8\x53\xe4\x14\x43\xc8\xcc\x75\x1d\x82\x15\x87\x8f\x69\x49\x46\xd7\xdb\x04\x57\xc5", 52, { 0xd5, 0x08, 0xaf, 0x1d, 0xfc, 0x44, 0x9d, 0x6a, 0x16, 0x7d, 0x5b, 0x43, 0xb5, 0xb4, 0xe8, 0xdb }, { 0x7b, 0x1b, 0xf7, 0x80, 0x09, 0x9b, 0x69, 0xfd, 0x28, 0xe3, 0xd3, 0xca, 0x7f, 0xaf, 0x43, 0x38 } },
{ "\x0e\x4c\xc1\x46\x66\x25\x59\x6c\x93\xdd\x26\x33\x57\xa4\xc2\xe6\x8f\x87\xc6\x27\x18\x3f\xbb\x96\xac\x74\xfe\x28\x09\xba\x0e\xe2\x5d\x51\x01\x25\xa9\x86\x94\x6b\xa0\x5a\xaa\x1f\xe2\x2a\x86\xa1\xbd\x53\xb5\x43\xd8", 53, { 0x19, 0x79, 0xac, 0x33, 0x2d, 0x89, 0xe8, 0x44, 0x32, 0x49, 0xdd, 0x27, 0x48, 0xea, 0xe6, 0xbd }, { 0x58, 0xba, 0xa1, 0x4f, 0x54, 0x23, 0x8a, 0x8d, 0xe0, 0x81, 0xbc, 0xc5, 0x21, 0x00, 0x58, 0xf3 } },
{ "\x0f\x70\xb2\xb4\x46\x72\x30\x4d\x06\x52\x8f\x42\x32\x56\xdd\xe8\x54\xc6\xdf\xa3\x6c\xf0\x00\x8b\xa9\x4a\x5c\xb9\xa4\xf8\x17\x1e\x69\xb3\x4e\x25\x6a\x90\xe5\x24\x3c\x5f\x21\xb1\x5e\x57\x18\x40\xbb\x75\x0d\x5d\xf7\x86", 54, { 0xce, 0x90, 0x6d, 0xbe, 0xa5, 0xe1, 0x73, 0x4f, 0x69, 0x27, 0x4c, 0x91, 0x6b, 0xde, 0x5d, 0x5b }, { 0x47, 0x5d, 0xb9, 0x45, 0xa5, 0x74, 0xc6, 0xff, 0xfa, 0x60, 0x6d, 0x86, 0x87, 0x20, 0x05, 0xbc } },
{ "\x51\x1c\xf4\x8b\x1c\x17\xa7\xa3\xce\x3d\xeb\x69\xe1\xc6\xb2\xd0\xba\xcd\x47\xb3\xce\x52\xab\x07\xa6\x21\x52\x4d\x14\x2b\x02\xa8\x37\x2c\x4b\xba\xf6\xae\xa8\xe3\x6c\xb7\xa5\x6d\x2f\x83\xae\x32\x5d\x23\x1c\xfb\xd9\x1a\x72", 55, { 0x9e, 0xdb, 0xec, 0x2a, 0xf9, 0x85, 0x76, 0x2c, 0xfb, 0x8f, 0x2e, 0x72, 0x6e, 0x1c, 0x16, 0xb6 }, { 0x6f, 0x3b, 0xe6, 0x0c, 0x03, 0x69, 0x05, 0x4d, 0x4d, 0x69, 0xd4, 0x5b, 0x7b, 0x7c, 0xe6, 0x5e } },
{ "\xc3\xa5\x63\x27\x07\x03\x7e\x34\xc8\x9f\x58\xb3\xe6\xab\x14\x35\x05\x6f\xd8\x2e\x47\xcd\xe9\x90\xb9\x42\x00\x48\x16\x85\xe8\xe5\xf9\xd7\x98\xc1\x11\xbb\xec\xfd\xf3\xea\x63\x41\x39\xed\xfc\xd7\x91\x84\x55\x82\x8e\xc2\xdb\xec", 56, { 0x39, 0x8a, 0xf1, 0xd1, 0xa5, 0xbe, 0xe0, 0xa4, 0x8f, 0x53, 0x0f, 0x29, 0x2e, 0x3e, 0x6f, 0xcc }, { 0xa2, 0x3d, 0x2e, 0xb9, 0xd3, 0x5f, 0xd3, 0xd7, 0x2a, 0x0c, 0xd1, 0x60, 0xf8, 0x2e, 0x84, 0x5b } },
{ "\xa3\x69\x74\x12\xad\xff\x5d\xf7\x4b\x7d\x29\xda\xf7\x2f\x9d\xda\x9a\x6b\x92\xdc\xc3\xde\xe5\x7a\x8c\xd5\xf1\x9f\xe0\xbd\x69\x66\x2e\x01\x3f\x45\x99\x4a\x8a\x66\xce\x67\xb4\xf4\xf6\xcd\x18\xf7\x23\x9a\xe2\x26\xdd\x1d\xab\x8f\xc4", 57, { 0xd9, 0x6c, 0x27, 0x09, 0x67, 0xc7, 0x35, 0xdb, 0x69, 0x3e, 0x5a, 0xa8, 0x03, 0x6c, 0x7d, 0x86 }, { 0x4a, 0x75, 0xbf, 0xa7, 0x85, 0xc9, 0xd2, 0x40, 0x52, 0xa9, 0xd0, 0x66, 0xf5, 0xd1, 0xe9, 0xc2 } },
{ "\x0a\x65\x70\xca\xca\x84\x29\x03\xe2\x13\x62\xe1\xe0\xe3\x06\xdb\x0a\x68\x46\x56\x24\x63\x0b\xe1\x2e\x32\xd3\x44\xef\x8b\x7d\x15\x47\x53\xec\x9b\x62\xea\x53\xa0\xcb\x16\x54\x46\xef\xe0\x8f\x4b\x5e\x43\x34\xd1\xde\xc4\x37\x3b\x8e\x7b", 58, { 0xb7, 0x84, 0x77, 0xc6, 0x0d, 0x64, 0xa9, 0x91, 0x4e, 0x25, 0x05, 0x35, 0xd4, 0x90, 0xf5, 0x9e }, { 0x22, 0x62, 0x04, 0x1b, 0x91, 0x4b, 0x2d, 0x7a, 0x7b, 0xd9, 0xb0, 0x36, 0xdd, 0xa5, 0xa6, 0x11 } },
{ "\x9b\x9f\xb3\x05\x6a\xc3\xad\x44\xe1\x8f\x19\x0d\xf4\x80\x2c\x67\x2a\x78\xbd\xa8\x7e\x57\x60\x19\x97\xda\x99\xd5\xde\x26\xec\x28\x8e\xdc\x2d\xf9\xa3\xce\x7e\x53\x67\xba\x75\x22\x4d\x81\xd2\x3d\x65\x81\x58\x5e\x8a\x15\xca\x73\x37\xe8\x91", 59, { 0x54, 0x0c, 0x29, 0x61, 0x6b, 0x3f, 0x76, 0x74, 0x9a, 0xe7, 0xb6, 0xf4, 0x2f, 0x10, 0xb2, 0x7a }, { 0xb2, 0xe0, 0xed, 0x09, 0x39, 0xe3, 0x74, 0x5d, 0x86, 0x13, 0x50, 0xe9, 0x6a, 0x6b, 0x6c, 0xaf } },
{ "\x93\xaf\xeb\x5b\x80\x30\x6d\x78\xdd\x49\x95\xe3\x14\xab\xad\x18\xce\x3e\xe7\x97\x12\x4c\x0d\x61\x47\x37\x9e\x66\xb5\xd2\x3c\x7a\x0d\x74\x0d\x15\x33\x6d\x3e\x31\xd8\x3c\xfc\x0a\x63\x38\x1b\x1e\xd4\x74\xdd\x59\x7b\x62\x21\xe2\x27\x1c\xcb\x56", 60, { 0x72, 0x58, 0x6b, 0x50, 0xe7, 0x76, 0x50, 0x62, 0x34, 0x12, 0xd9, 0x25, 0xd5, 0xf5, 0xf0, 0x1a }, { 0x5c, 0x0a, 0xd5, 0x60, 0x95, 0x80, 0xe9, 0x02, 0x9e, 0x47, 0xf4, 0x3d, 0x3a, 0xdf, 0x6d, 0xa9 } },
{ "\x53\x7a\x16\x8f\x2e\xf8\x1d\x8d\xc4\x18\xb9\xc3\x34\xf9\x5a\x82\xb9\xae\x98\x65\xb2\x72\xd7\x2b\x30\xbc\x05\x0e\xb6\xb0\x3b\x2d\xa3\xcb\x0e\x93\x9c\x77\x81\x51\x12\xea\xe3\x49\x4d\x99\x52\xed\x16\xba\xf4\xc0\x3b\x99\x88\x96\x33\xb1\xad\xa2\x43", 61, { 0x64, 0xec, 0x37, 0x91, 0xd0, 0x66, 0xae, 0xb7, 0x15, 0x3a, 0x5a, 0x47, 0x1d, 0x6b, 0x7f, 0xe4 }, { 0x0f, 0x83, 0x06, 0xff, 0x82, 0x1f, 0xbb, 0xef, 0x77, 0x5d, 0x8a, 0x33, 0xa2, 0x23, 0x11, 0xaf } },
{ "\xe1\xa4\x4a\x9c\xac\x7e\x7c\xf2\xe3\x61\xeb\x2f\x4b\x0e\x5c\x33\x2c\x17\x5b\xa3\x62\x89\x92\x74\xc7\x41\x3d\x0a\xc1\x13\x3b\x3e\x2d\xd8\x6b\x23\xff\x98\x89\x22\xe2\x52\x4e\x97\xcf\x38\xad\x13\x62\xb2\x1b\x25\x40\xc4\x73\xb6\xd7\x52\xc3\x66\x88\x2c", 62, { 0x30, 0x78, 0xcf, 0x91, 0x9b, 0x27, 0x59, 0x79, 0x19, 0xb6, 0xff, 0x27, 0x37, 0x49, 0xa4, 0xbd }, { 0xe9, 0xf1, 0xd8, 0x86, 0x35, 0xa0, 0xbd, 0x12, 0x16, 0x24, 0xce, 0x92, 0x12, 0xf1, 0xaf, 0xdb } },
{ "\xff\xdf\xe1\x8e\x76\x07\x58\x47\x95\x0d\x4e\xcb\xf7\x5d\x66\x6f\xe9\xfc\x50\x17\xc0\x41\xd3\x3c\x59\x16\x90\xe1\x4d\xe5\xf5\x4b\xef\x0a\x81\xae\x86\x6f\x3b\x12\x44\x85\xf3\x1c\x3d\x2b\xdb\xdd\x98\xc9\x68\xab\x3f\xc2\xed\x88\x80\x80\x9f\xd4\xa5\xe8\x2d", 63, { 0x22, 0x78, 0x55, 0xa2, 0x9a, 0xa2, 0xd6, 0x8a, 0x3e, 0x38, 0x58, 0xb1, 0xaa, 0x54, 0xb6, 0x78 }, { 0xe4, 0x23, 0xc9, 0xe6, 0x86, 0x5e, 0x44, 0xa9, 0xe7, 0x7d, 0x09, 0x5d, 0x70, 0xf9, 0xa1, 0xb8 } },
{ "\x97\xe6\xe1\x6c\x24\x3e\xc0\xc8\x83\x5e\x29\x6d\xed\x98\x2a\x49\x8f\x3a\x18\xf2\xc7\x5b\x5f\x23\x6e\x74\x8c\x57\xdb\x40\x5f\x92\x32\x74\x9d\x41\x85\x66\x28\x8a\xab\xcf\x3d\x92\xcd\x15\x13\xd4\x3b\x22\xc3\x8b\x94\xf7\xe5\xbf\x80\x30\x4e\x8a\x40\x82\xa4\xe3", 64, { 0xc3, 0x05, 0xc7, 0xba, 0xd0, 0x8c, 0xcc, 0x94, 0x7e, 0xb2, 0x62, 0xe5, 0xbc, 0xe9, 0x4d, 0x43 }, { 0x02, 0xe3, 0x87, 0x71, 0xd4, 0x70, 0x92, 0x44, 0x1c, 0x69, 0xe5, 0x3b, 0x80, 0x92, 0xb9, 0x14 } },
{ "\xe3\xbf\xaf\x7f\xfd\x39\xbb\xab\xf9\xa8\x0b\xb0\xde\x6f\x97\x1e\xcd\xcf\x3f\xef\x5a\x07\x40\x44\x51\x06\xa5\x07\x1e\x50\xd2\x48\xa9\x53\x79\x0d\x8e\x74\x51\xc0\xfe\x98\x38\xf7\x71\xae\xfa\xdc\x86\xf9\x50\x92\x7e\x72\x63\xc8\xdb\xa9\x1d\x37\x2a\x7b\xe8\xf4\xf5", 65, { 0xd4, 0xd3, 0x0f, 0x48, 0x4a, 0xdc, 0xef, 0x5f, 0xad, 0x08, 0x10, 0xaf, 0x40, 0x60, 0xda, 0x33 }, { 0xba, 0x4e, 0x94, 0x7c, 0x06, 0x8d, 0x1a, 0xd7, 0x68, 0xe9, 0x57, 0xcf, 0x41, 0x3a, 0xc6, 0x60 } },
{ "\x74\x1e\x33\x3a\xec\x42\xc1\x54\x55\x80\x6c\xec\x76\x42\x09\xcc\x32\xbe\x6c\x43\xac\xa2\x70\xe1\xc7\x2e\x4d\x94\x47\x8e\x30\x36\xc7\x99\xe5\xbf\x0a\x8e\x96\xa8\xed\x55\x3b\xd5\x4f\x03\xdb\xcb\x26\x8d\x10\xbc\x63\x28\x0e\xc1\x08\x4f\x35\xab\x1c\x05\xe7\x7e\x40\xb7", 66, { 0x28, 0x7f, 0xba, 0xfe, 0x13, 0x9c, 0xc9, 0xf4, 0x3a, 0x6b, 0x6c, 0xa9, 0xe2, 0x4c, 0x42, 0x65 }, { 0x5e, 0xe2, 0x93, 0x10, 0x4f, 0x48, 0x0b, 0xa1, 0xb2, 0xd0, 0x36, 0x4b, 0xa7, 0xd6, 0x11, 0xae } },
{ "\xfc\x04\x08\xf9\x49\x2b\x9b\x72\x50\x8b\x59\xaf\x43\x39\x7a\x82\x3d\x56\x36\x16\x2d\xe9\xc1\x6c\xf7\x80\xac\x28\x49\x1e\x51\x1f\x7d\xed\x95\xd2\x1d\xf8\x02\x36\xab\xb1\x0b\xc7\x24\xf2\x92\x30\x5f\x2d\x14\x77\xbe\x2b\xd9\x2e\x90\x89\xb8\x6c\xbd\x76\x0b\x7b\x32\xb6\x31", 67, { 0x0d, 0x79, 0x17, 0x11, 0x23, 0xe3, 0xae, 0x32, 0x9f, 0xa8, 0x23, 0x5e, 0x76, 0x00, 0x8e, 0x0b }, { 0xbf, 0x9a, 0x49, 0x8d, 0x98, 0x3a, 0x1f, 0x54, 0x64, 0x57, 0xe7, 0x6b, 0x55, 0x35, 0xcb, 0xf2 } },
{ "\x18\xde\x21\x51\x47\x89\x11\x02\xe2\xf7\x6f\x90\xb2\x09\xe3\x49\x38\x1c\x43\xf1\x38\x7e\xc6\x83\xb2\x34\xad\x6f\x62\x88\x8f\x5c\x09\x75\x75\x1d\x05\x0e\xe0\x92\xe6\x3a\x8d\x8d\xeb\x30\xb7\xd1\x50\x12\x60\x37\xea\x94\xe9\x02\x74\x3a\xb4\x06\x67\x36\xb2\xdc\xad\x04\x77\xaf", 68, { 0x5f, 0xbe, 0x0e, 0x35, 0x05, 0x34, 0x56, 0x50, 0x6d, 0x40, 0x94, 0x7b, 0xde, 0x20, 0x48, 0x2d }, { 0xc2, 0x32, 0xe4, 0x2b, 0xb7, 0x1a, 0xb4, 0xd5, 0x36, 0x11, 0x7c, 0xb7, 0x34, 0x44, 0x41, 0x6a } },
{ "\x0d\x13\x37\xc4\xb6\xcb\xd4\x52\xbc\x03\x91\x88\xea\xf4\x77\x82\x94\x9e\xbf\x63\xde\x73\xc6\x2f\x31\x5c\xf2\x7c\x27\xd5\x8f\x39\x99\x59\x3b\xdc\x06\xfc\xba\xf1\x76\xe4\x13\x8b\x38\x1c\xb8\x11\xca\x67\x46\xc2\x36\xd2\xd1\x6c\xbd\x34\xeb\xad\x23\x72\x0d\x2f\x56\x61\xd0\x9e\x3c", 69, { 0xb1, 0xd6, 0x81, 0x66, 0x10, 0xc0, 0xc6, 0x8d, 0xde, 0x14, 0x94, 0x3f, 0x11, 0xaa, 0xab, 0xd9 }, { 0x42, 0xe9, 0x13, 0x96, 0xf0, 0x33, 0x1c, 0x74, 0xd8, 0x6e, 0x16, 0x53, 0x27, 0x00, 0x27, 0x3a } },
{ "\xe0\xeb\xdf\x93\x5b\x94\x3e\xc4\x76\x6d\x3f\xc0\x11\x23\x29\x99\x43\x74\xd0\xe8\x3b\xa7\x9b\x7b\xbb\x7c\x74\x16\x16\xed\x1c\x07\xac\xe1\xdf\xdf\xac\x02\xad\x38\x9c\x65\x4c\x1d\x28\xf7\xf1\x12\xb3\x9c\x3c\xed\xc5\x91\xeb\x8f\x62\x16\xed\x5d\xf0\xba\x78\x50\x55\x24\x84\xb4\x2f\xa6", 70, { 0x9f, 0xde, 0x22, 0xec, 0xc4, 0x47, 0x72, 0x5c, 0xee, 0xe4, 0x77, 0x1f, 0x4b, 0x8d, 0xf4, 0x6b }, { 0x10, 0x73, 0xd8, 0xce, 0xd7, 0x4b, 0x46, 0xb4, 0x65, 0x24, 0x4c, 0xd1, 0x4e, 0x65, 0x85, 0x8d } },
{ "\x9d\x25\x31\xc4\x30\x64\x8d\x7f\x7b\x95\x63\xf4\xdf\xc4\xeb\x51\x01\x40\x3b\x3d\x51\x69\x46\x49\x07\x95\x84\xf8\x98\x26\xfb\xd2\xd4\x26\xae\x62\xbf\xdc\xda\x15\xc6\xd4\x37\x11\xa6\x23\xde\x91\xe9\x3f\x49\xb9\x9a\x5a\x86\x9e\x0a\x6c\x3f\xb6\x94\x68\xc5\x7f\xa8\xbe\x90\x26\x69\xc5\x38", 71, { 0x25, 0xa6, 0x9f, 0x8d, 0x7f, 0xd1, 0x93, 0x77, 0x85, 0x1d, 0x10, 0x0e, 0x7e, 0xdf, 0x5d, 0x8f }, { 0x4d, 0x90, 0xa8, 0x60, 0x57, 0x18, 0xdc, 0x61, 0xc9, 0x99, 0x05, 0x35, 0xa1, 0x92, 0x8a, 0x7d } },
{ "\x38\x95\x55\x5e\x1e\x71\xee\xe8\x57\x94\x21\xed\x4c\xcc\x1b\x1c\x99\xcb\x67\x6e\x61\x2f\x81\x09\xc5\xd0\xbf\x37\x1e\xd1\x24\x35\x77\xea\xe2\xba\xdd\x2b\xa3\x99\xce\xce\xf7\xa5\x33\xd6\xb9\xa2\xcc\xbd\x52\xa5\x94\x07\xb2\xd0\x9e\xcc\xff\x54\x18\xa5\xf9\x6e\x56\x85\x59\xd7\x88\x12\xd8\x8a", 72, { 0x76, 0x83, 0x4a, 0x11, 0x34, 0x5c, 0x50, 0x15, 0x38, 0xac, 0x0f, 0xa1, 0xd5, 0xf6, 0x14, 0x53 }, { 0xfa, 0xb8, 0x79, 0x41, 0x63, 0xb6, 0x10, 0x66, 0xa7, 0x17, 0x04, 0x06, 0xea, 0x1e, 0x8d, 0xda } },
{ "\x47\x7d\x03\xda\xa2\x53\x60\xde\xe5\xf3\xfc\x0a\x2a\x2a\x2d\xec\x7f\x99\x90\xa0\x7b\x71\x75\x67\x34\x87\x02\x7b\x5e\x7c\xb4\xf0\x16\xbb\x46\x25\xe9\xba\xf2\x4e\xff\x35\x61\x91\x4b\x86\xd2\x01\x22\x66\x10\x27\x45\xcd\x74\x99\xbe\x30\xa2\x28\xaa\x44\x8d\x3b\x18\x41\x6e\xe3\x2c\xa4\x98\xbe\x28", 73, { 0xe9, 0x61, 0x66, 0x22, 0x9f, 0x85, 0x83, 0xa6, 0x39, 0x70, 0xf5, 0x66, 0xa9, 0x50, 0x68, 0xcd }, { 0xcb, 0xd5, 0x0e, 0x40, 0xb2, 0xe3, 0xaf, 0xe7, 0x80, 0x87, 0x84, 0xe8, 0xe8, 0x41, 0xb2, 0x86 } },
{ "\x3f\xc0\x1b\x48\x37\x3c\x99\x44\xa6\xa2\xad\x32\x8b\xde\x91\xf9\xd5\x5c\xdc\x09\x27\x24\xee\x86\xa3\xde\x12\x19\x8d\x35\xf6\x9a\xec\x05\x2f\x05\x76\x25\x30\x05\x8f\x76\xdb\xbd\x52\xb5\xca\x3b\xd0\x95\x9e\xcd\x75\x17\x0b\x5b\xf7\x1c\xc4\xb4\x3f\xc8\xb9\x23\x80\x4c\xba\x64\xc6\x38\x14\xe8\x50\x64", 74, { 0x19, 0x0b, 0x19, 0x07, 0x0e, 0x14, 0x85, 0x4b, 0x38, 0x89, 0x01, 0x66, 0x1b, 0x2b, 0x39, 0x17 }, { 0xbb, 0xba, 0x25, 0xca, 0xad, 0x34, 0x5c, 0x9d, 0x93, 0x40, 0x25, 0x82, 0xdf, 0xa3, 0xb9, 0x4b } },
{ "\xe3\x26\xc2\x55\xcd\x13\x71\xc0\xa2\x9d\xf2\x26\xdb\xdc\x4e\xec\x2f\x47\x24\xd0\x72\x4b\x4a\x12\xa7\xae\xdf\xd1\xe9\xdc\xda\xf1\x02\xad\xe5\xcc\x54\xf2\x91\xd6\x3a\xc6\x5a\x32\x77\xb2\x43\x50\x18\x17\xbb\xb6\x8a\xb8\x14\x81\x7c\xe6\x0a\xf2\xfe\x95\x34\x54\x2b\x93\x9a\x8c\xa4\x56\x72\x62\x2b\xc2\xdb", 75, { 0xb3, 0xac, 0x3c, 0x16, 0x7d, 0x9c, 0x5e, 0xc1, 0xd1, 0x45, 0xc7, 0x63, 0x2b, 0xf2, 0x93, 0x6e }, { 0x10, 0x13, 0xd5, 0x36, 0x82, 0x93, 0xfc, 0xaf, 0xcf, 0xba, 0x70, 0xe5, 0xc4, 0x64, 0x74, 0x63 } },
{ "\x18\x91\xd2\xe5\x30\xe3\xff\x36\xd5\x29\xc2\x01\x00\xef\xbe\x99\xf0\xdd\xd2\xb6\x5c\xed\x88\x06\xd9\x8a\x0f\x43\xc7\x51\xe4\xb3\xc3\x9a\x0a\x51\xe3\xe4\xdb\x59\x21\xaf\xe6\x8c\x1d\x7d\xfc\xd9\x27\x53\x2d\x59\x06\xc6\x92\x83\x19\x78\xbc\xfd\x48\x13\x7e\x75\xe5\x4e\xa3\xb5\x0a\x74\x05\x0d\x16\xe9\x16\xce", 76, { 0x86, 0x35, 0x23, 0xf1, 0xd1, 0xba, 0xb0, 0xdd, 0x96, 0x53, 0xe6, 0x23, 0xda, 0x9b, 0x86, 0xf6 }, { 0x4f, 0xa0, 0xcf, 0xeb, 0xdb, 0xb4, 0x0e, 0x43, 0xa4, 0xe0, 0x20, 0x27, 0x87, 0xcb, 0x3a, 0x9a } },
{ "\x01\x9d\xc5\x59\x43\x36\xad\x4d\x34\x16\xf6\x4b\xb0\xc8\x96\x7a\xf2\x9a\xfa\xc9\xd0\x4c\x4e\xcc\x14\x5f\xc4\x17\x56\x3e\xd5\xe9\xd3\xe9\x57\x03\x0e\x02\xf0\x23\x27\x20\xeb\x64\xb3\x36\x74\x62\xcd\xfb\xc6\xf6\x8d\x9e\x0b\x8d\x0a\x17\xb6\x02\x1e\x68\x93\x98\xf7\xd9\x72\x5e\xb6\xcc\xe6\x01\xf3\x37\x2a\xea\xd3", 77, { 0xb3, 0x76, 0x7f, 0x4d, 0x81, 0xde, 0x88, 0x33, 0x2e, 0x43, 0xea, 0x4f, 0xf7, 0x12, 0x39, 0x5f }, { 0x03, 0xeb, 0xd8, 0x2c, 0x3a, 0x39, 0x86, 0xda, 0xe2, 0x69, 0xd0, 0x67, 0x51, 0x50, 0x9d, 0xb5 } },
{ "\xec\xa4\xa3\x87\x39\x5e\x8f\x16\xbc\xfc\xa0\x59\xd3\x50\xf1\xce\x61\x49\x9e\xdf\x0d\x00\x62\x70\x9e\xc2\x5d\x69\x53\x4a\x83\x74\x22\x7d\xbf\xac\xdf\x47\x8e\x59\x7e\xec\xb6\xa1\xd2\xb2\x4b\x53\x36\x09\xd5\x03\x86\xde\xf7\x0a\x2a\x8f\xba\x38\x11\x80\x59\xf4\x41\x06\x38\xfa\x03\x1f\x39\x18\xdf\xc0\xc8\x69\x95\xce", 78, { 0xbd, 0xc0, 0x7f, 0x12, 0xf6, 0xde, 0x13, 0x57, 0x64, 0x68, 0x30, 0xa0, 0x3f, 0xee, 0x93, 0x07 }, { 0xb6, 0x66, 0xcd, 0x74, 0xa9, 0x8a, 0x84, 0x92, 0xbb, 0x5f, 0x30, 0x8b, 0x4e, 0x54, 0x5a, 0xce } },
{ "\xd6\x62\x73\x8a\xac\x3e\x70\x2a\x24\x72\xca\x8a\x52\x78\x78\xc7\x2d\xa7\xad\x7a\xcf\x20\x6d\xc8\xba\x75\x40\x9b\x34\xe4\x5a\x18\x7a\x2d\xcb\xf9\x6a\xcc\xe1\x82\xd4\xd0\xa3\xc7\x82\x21\xba\x40\x46\x17\xde\x3d\x01\x5f\xaf\xac\xb1\x69\xac\x2a\x3a\xaf\xe6\xde\x6d\x47\x49\xce\xda\xbe\x4e\x82\x84\x3a\x4b\x12\x8a\xd7\xdc", 79, { 0xde, 0x8c, 0x2f, 0xef, 0x77, 0xcc, 0x2e, 0xb5, 0x3d, 0x63, 0xd9, 0x4d, 0xa2, 0xcd, 0x09, 0x10 }, { 0xb4, 0x7e, 0x4b, 0x9a, 0x72, 0x4d, 0x07, 0xa7, 0xf0, 0x3b, 0x8f, 0x69, 0x22, 0xfc, 0xa1, 0xdc } },
{ "\xfe\x6d\x2c\x1c\xf5\x5f\xea\x1f\x30\x7a\xc8\xab\xe9\xd6\xd6\xe1\x78\x95\x20\x58\xe6\x42\x28\x52\x67\xc2\xca\xa8\x3b\xf0\x3e\x1d\xa2\x88\x2d\x83\x46\xfc\x53\xd4\x1a\x67\x44\x8c\x3f\xfd\xb6\x8c\xc0\x7b\x84\x86\xc5\x9c\x3a\x38\x8a\x8d\xd6\x2f\xb6\x1d\xa8\xc7\x6f\x62\x27\x19\x1e\x71\xa3\x29\xe5\x89\x54\xdd\x70\x55\x9a\x4e", 80, { 0x44, 0x04, 0x9a, 0xb4, 0xc1, 0x51, 0x55, 0x2f, 0x46, 0x78, 0x9b, 0x01, 0xa9, 0xb5, 0xeb, 0xf9 }, { 0x1b, 0x65, 0x4e, 0xb7, 0xf1, 0xf0, 0x66, 0x63, 0xf6, 0xb0, 0x36, 0x43, 0x89, 0x80, 0x5b, 0x7d } },
{ "\x34\x54\xd8\xea\xe9\xa5\xdb\xf9\x13\x3b\xf8\x54\xd9\xa4\xe9\xaf\x63\x33\x07\x67\x25\x5f\x33\xe3\x44\x1e\x30\xd7\xa4\xef\x2f\x4d\xbc\x5f\xc6\xe3\xd3\xb1\xba\x2f\x14\xdc\x03\x3f\x66\xc6\x25\xa0\xd3\x0d\x60\x66\x9b\x7a\x5d\x2b\xee\x27\x16\x7e\xde\xa8\x21\xae\x85\x3f\x50\xee\x7a\xa8\xe6\x4e\x45\x52\xdf\x85\x4d\x9c\xb0\x4a\x1f", 81, { 0x61, 0xec, 0x00, 0x32, 0x6a, 0x02, 0xd4, 0xaf, 0xe7, 0xa0, 0xce, 0xca, 0x60, 0xef, 0x21, 0x92 }, { 0x82, 0x50, 0x00, 0x25, 0x68, 0x9d, 0xbc, 0x20, 0x51, 0xe9, 0x75, 0x57, 0x7c, 0x69, 0x6f, 0xa9 } },
{ "\xa5\xc5\x9a\x8e\xee\x1b\x35\xfa\x65\x18\x03\xd6\x9f\x61\x9f\x62\xf0\xa8\xd0\x6a\x0a\x22\xba\x67\x84\x98\x8d\xeb\x87\xe3\x58\x18\x24\x28\x70\x5f\xbf\xe8\xb2\x8a\x4f\xf3\x7e\xc5\xa5\xba\x0b\xde\xe9\x98\x33\x64\xad\x87\x22\x1c\xfd\xf8\xb1\xe8\xf4\x7c\x12\x1e\x02\xb8\x94\xa5\x07\x34\x34\x5e\x46\xc9\x59\x7c\xdd\x31\x0a\xb7\x81\xc0", 82, { 0xea, 0xbd, 0xf0, 0x95, 0xca, 0x4a, 0x07, 0x9c, 0x7f, 0x66, 0xff, 0xe6, 0x54, 0x18, 0xdc, 0x51 }, { 0xb8, 0x3b, 0x84, 0x10, 0x22, 0x1d, 0x88, 0x08, 0x34, 0x48, 0x19, 0x67, 0xdc, 0x0d, 0x51, 0x2b } },
{ "\x0a\xda\x5b\xde\x2f\x73\xbf\x71\x6d\xc6\x87\xe5\xf8\xdc\x31\x86\xd8\xe1\xe1\x64\xed\x7a\xb2\x81\x5f\x49\x04\xcb\x1d\xce\x42\x58\x88\x98\x01\x7a\x9a\x45\xc7\xca\x75\x74\xf7\x5c\x24\x4f\xd9\x71\xf8\x59\xae\xe0\xfe\x5a\x2b\x41\xe6\x71\x66\x4e\x0a\x43\x7d\xdc\x57\x84\x44\x5d\x39\xdd\xed\xf5\x10\xe3\xc4\x2f\x07\x00\x67\xb3\xe5\x6a\x52", 83, { 0x4a, 0x5f, 0x79, 0xb2, 0xe8, 0x2c, 0x5f, 0x29, 0xce, 0xe6, 0xe9, 0x35, 0x5e, 0x9f, 0xd9, 0x16 }, { 0xa7, 0x85, 0x73, 0x73, 0x27, 0xa1, 0x3b, 0xf0, 0xbb, 0x1e, 0x62, 0xa1, 0x89, 0xde, 0x41, 0xa8 } },
{ "\x8d\x4d\x67\x8f\x4f\xa6\x62\x34\xb5\xa7\x96\xff\xdf\x32\xef\xdc\x88\x05\x96\x41\x1f\x5f\xb5\x02\xf9\x72\x1c\x2c\xb7\x5e\xa9\x81\x42\x68\x05\x02\x68\xa9\x71\x19\xc5\xc6\xe6\xc5\x3c\x37\xf6\xd7\x08\x85\x06\x07\x86\x73\xd7\x27\x51\xae\xf3\xdb\x3a\x95\xc4\x98\x66\x80\x16\x50\xe1\xbb\x72\x40\x46\x3d\x5f\xbe\x38\x84\xed\x78\x17\xb4\xc7\x8c", 84, { 0x4f, 0xfd, 0x29, 0x18, 0x06, 0x6e, 0x13, 0x44, 0x3e, 0x22, 0xed, 0x6a, 0xb4, 0xb7, 0x09, 0x06 }, { 0x8d, 0x59, 0x8a, 0xad, 0x1f, 0x32, 0xf9, 0x6a, 0xef, 0x22, 0xf3, 0x7a, 0x4c, 0xe0, 0x94, 0xdf } },
{ "\x1c\x5e\x5d\xf3\x52\xc1\x37\xf5\x02\x4f\x8b\x52\xd0\x84\x58\xa8\x10\x13\x81\x9c\xe3\xe4\xb2\xc3\x0e\x5d\xeb\x98\x94\x70\xfd\x68\xf6\x0f\xc5\x7c\x84\xdb\x2d\xde\x37\x15\xd9\xb8\xf1\x1c\xd5\x25\x3e\xb3\xef\xef\x8c\xa4\xad\xff\x2f\xf8\x65\x7a\x5a\x4e\xe0\x25\x04\xe4\x42\x2f\x53\x9b\x8b\xbd\x15\x90\xd8\xa8\x34\x7f\x69\xcc\xaf\x47\xd5\x0d\xd7", 85, { 0xae, 0x2f, 0x95, 0xa2, 0xdb, 0xf3, 0x3d, 0xb1, 0x4f, 0x11, 0x3d, 0x76, 0xcc, 0xf5, 0x9d, 0xa2 }, { 0x50, 0x39, 0xe8, 0xd0, 0x07, 0x0f, 0x04, 0xd0, 0x26, 0x21, 0x97, 0x29, 0xdc, 0x3e, 0x19, 0x8f } },
{ "\x61\x6c\xf4\x0e\xd5\x90\x2e\x13\x9f\xf7\x83\x61\xdc\x0b\x20\xd7\xdc\xc6\x6a\x83\xb0\x56\x72\xe6\x80\xd8\x05\x25\x94\xde\xd4\x23\x87\x4d\x10\xb3\x63\xa6\x68\xf5\x58\xea\x63\x5c\x1a\x4e\xf9\xc0\xbd\x8c\x55\x40\x39\x17\x1d\x19\x39\x1a\x1d\x9b\x30\xf0\xda\x5d\x2c\xb7\xd8\x47\x87\x14\xfb\x37\x01\x20\x81\x1a\x33\xd2\x18\x79\x59\x65\x90\xae\x8d\xb3", 86, { 0x58, 0xd6, 0x31, 0x61, 0xf6, 0x31, 0x76, 0x89, 0x0b, 0xd9, 0x4f, 0x77, 0x45, 0x0d, 0x71, 0x5a }, { 0x4e, 0x27, 0x6d, 0x04, 0xe6, 0x3a, 0xd7, 0xfe, 0x99, 0x60, 0x0f, 0xb4, 0x5c, 0xb7, 0x99, 0xc5 } },
{ "\x9f\x82\x55\x51\x54\x32\x7d\xf7\x9b\xdc\xdf\x8f\x74\xf4\x02\x46\x99\x07\x84\x85\x42\x6f\xb6\xb6\x29\xa9\x31\x2f\x6f\x89\xe4\x10\x98\x0f\x91\xdd\xa2\x07\xc8\xbb\xff\xef\x2a\xac\x97\x82\xd2\xb7\x37\x91\xc2\x57\x18\x59\x61\x2c\x2f\x15\x95\xf0\xb0\xc4\x6a\xf1\xff\x5f\xc4\xf4\x11\xb0\x08\x11\x1d\x22\xd8\x16\xa8\x69\x77\x1c\x38\x66\xbf\x28\xb0\xaa\x7b", 87, { 0xf9, 0x5c, 0xdd, 0x09, 0x7f, 0x10, 0x73, 0x9c, 0x94, 0xea, 0xbb, 0x56, 0x1b, 0x22, 0x35, 0x9a }, { 0x8c, 0x6e, 0x67, 0x84, 0x76, 0xa6, 0xf0, 0xa8, 0xf5, 0x78, 0x68, 0x2f, 0x68, 0x1c, 0x70, 0x41 } },
{ "\x4a\x50\xf2\xea\x13\x95\xb3\xdd\x77\xa6\x11\x26\x38\x98\x2e\x41\xea\xb0\x87\x14\xce\xa7\xa2\x6a\x7e\xcd\xf8\x16\xc2\xf0\xe9\xe0\x16\x0c\xeb\x03\x69\x59\xfb\x39\x2c\x94\xab\x0d\xa0\xa5\x47\x7c\x3b\x98\xfa\xef\x81\xd5\x25\x1f\x09\x59\x56\xff\x99\x6f\x82\x42\x9c\x0c\x24\x30\x04\xaa\x66\x7e\x1b\x61\xe5\xff\x35\x4c\x03\x33\x6c\x8c\xe5\xcd\x21\xd0\xfa\xe2", 88, { 0x73, 0xea, 0xef, 0x15, 0xfb, 0x6b, 0x63, 0xec, 0x79, 0xf3, 0xec, 0xac, 0x3a, 0xf0, 0x9f, 0x29 }, { 0xb2, 0xb4, 0x30, 0x97, 0x7a, 0x75, 0x3f, 0xc0, 0x7a, 0x67, 0x74, 0x23, 0x45, 0x60, 0x1f, 0x6c } },
{ "\x16\x3b\x98\xeb\xfc\x52\xb5\x5c\xc2\x01\x6f\x61\xcf\xb4\x27\x09\x6c\x70\x0c\xd5\x6b\xed\x6b\xeb\x2a\x0a\xba\x93\x32\x18\x57\x19\x31\xb8\x30\xe2\x8a\x0f\x3c\x8d\x88\xff\xa8\x3d\x28\x09\x1b\xde\xa0\x7a\x7c\x21\x11\xd8\xc0\x3f\xa3\x83\x0f\xca\xe4\x82\x65\x2a\xec\xa5\x8f\x68\x10\x58\x04\x9e\x81\xd4\x08\x47\xb5\x46\xb5\x42\x12\xb4\x1d\x37\x62\xda\xe1\xfd\x2d", 89, { 0xd2, 0x9a, 0x9e, 0x07, 0xef, 0x02, 0xd4, 0x12, 0xaa, 0xc4, 0x85, 0xc9, 0xc0, 0x07, 0xe9, 0xb6 }, { 0x8d, 0x10, 0x39, 0x11, 0x29, 0xf3, 0x64, 0xeb, 0x7c, 0x74, 0xc9, 0x57, 0x17, 0x94, 0x11, 0x9b } },
{ "\x32\x0b\x82\xae\xea\x1e\xd7\x76\xe9\xda\xda\x56\xcd\xcb\x4c\x27\x03\x4a\x87\x52\xe9\x48\x2d\xeb\x7f\xd5\x60\x7d\x47\x54\x50\x0c\x8d\xc9\x57\x20\x21\xf8\x0d\x9c\x7f\xec\x55\x63\x25\xf6\xab\xd6\x38\xc5\x26\xc7\x3d\x93\xd9\x7f\x81\x73\x16\xd0\x88\x45\xef\x67\x41\x3d\x36\x40\x77\x58\x03\xb3\xf1\x8f\x00\x39\x23\xcf\x75\xf9\xd2\x06\x16\x0f\xad\xce\x6c\xf3\x0c\xd5", 90, { 0x9f, 0x07, 0x94, 0x3c, 0xbd, 0xd3, 0xbc, 0x92, 0x60, 0xaf, 0x17, 0x0a, 0xc6, 0x6c, 0x44, 0x36 }, { 0x1a, 0x79, 0xf6, 0x17, 0xda, 0xf7, 0x74, 0xa4, 0x1a, 0xb6, 0x50, 0xe4, 0x71, 0x4b, 0x3f, 0x1d } },
{ "\xe1\x1a\x5d\x1c\xf4\xff\x2c\xf1\xec\x17\x5a\x92\x66\xcf\xa6\x11\xd4\x9b\x7d\xa8\xdf\xa7\x9c\xb6\x75\x35\xb0\x6b\x40\xe1\xe0\x41\x53\xb0\x0b\x1a\xe1\xb8\xec\xd0\xcb\x07\x71\xa6\x4d\xcd\xed\xbe\xec\x7e\x75\x7b\x85\xf8\x7d\x2a\x41\x26\x30\xc0\xf4\xf7\x8d\x46\xe5\x77\xa1\x78\x86\x18\xbc\xcc\xbd\x65\xc6\x21\x4a\xac\x0e\x78\x8d\x6f\x77\x6e\x91\x74\x96\xcf\x4b\x57\x45", 91, { 0x99, 0x1e, 0x6f, 0x05, 0x36, 0xf3, 0x50, 0xb4, 0x32, 0x9f, 0x67, 0x96, 0x1e, 0x19, 0xf6, 0xac }, { 0x59, 0x1a, 0x28, 0x99, 0xe0, 0x0c, 0x0e, 0x06, 0x16, 0xff, 0xf0, 0x5f, 0x02, 0x74, 0x04, 0x2d } },
{ "\x4d\xcf\xdc\xd9\xbb\xd0\x66\x5e\x96\x72\xdb\x95\x45\x05\xde\x32\x0c\x81\x62\x41\xc7\xc8\x1b\x06\x32\xab\x40\xbb\x4f\x9f\x0b\x74\x29\x66\x81\xd7\x64\x90\x54\x26\xe8\x28\x84\xb5\x34\xb9\xd9\xce\xae\x48\x0d\x14\x16\xf7\xe4\x53\x4d\xbb\x7e\xb6\xcf\x0e\x25\x4a\xac\x47\x30\xf1\x91\x5c\xe6\xa0\x70\xa3\xb3\x60\xa7\x77\x0f\x4b\x2d\x6c\x1d\x9b\x7f\x63\xff\x20\x14\xad\x17\x41", 92, { 0x43, 0x66, 0xe2, 0x66, 0x26, 0x23, 0xec, 0x39, 0xb2, 0x14, 0x48, 0x38, 0x16, 0xf2, 0x89, 0xa8 }, { 0xa7, 0xcf, 0x17, 0x9b, 0x69, 0x56, 0x02, 0xa6, 0x02, 0x79, 0xfb, 0x1e, 0xe8, 0x36, 0xf2, 0x48 } },
{ "\x19\x55\xe4\x94\xd9\x04\x1f\x63\x2f\x91\x86\x91\x93\x09\x8f\x60\xa6\xfc\x47\xf3\x4d\x64\xb1\x01\xf4\x6e\x28\x8a\xfd\xa2\x98\xe9\xde\xa9\x64\x16\x94\xc7\x95\x1c\xfc\xf1\x8b\xe9\x22\xf8\xad\xd7\xf6\x0d\xc0\x98\x37\x91\x37\x61\x9a\xde\xb1\x1e\x9a\xc6\x86\xc6\x26\x81\x13\x5c\x97\x42\xb5\x9d\x63\x0a\xe6\xdb\x79\x49\xaa\x58\xf3\x0e\xeb\x80\x30\xd2\x07\x4f\x5f\x89\x52\x70\x91", 93, { 0xfe, 0x43, 0x5d, 0xc0, 0x6d, 0xfd, 0x7b, 0x06, 0x8a, 0x53, 0xaa, 0x17, 0x8f, 0x50, 0x9e, 0x01 }, { 0x82, 0x2c, 0x32, 0x35, 0x21, 0x6a, 0x42, 0xef, 0x6a, 0x01, 0xf8, 0xe3, 0x5e, 0x68, 0x8d, 0xf3 } },
{ "\x48\x69\x78\x9d\x87\xfd\x3d\x34\xd9\x61\x2c\xc3\x2f\x9b\xf0\xa1\xf3\x59\x3b\x84\x24\x48\x25\xeb\xee\x21\xeb\x2b\x2d\x1e\x5b\x9e\xa0\x3e\x8f\xdd\xb5\x38\x71\x28\x9c\xca\x96\x5c\xd0\x51\xfa\x50\x49\xd9\xfc\x76\xd8\x9c\x5b\x69\xfa\x0c\x17\x76\x1c\xf0\xdf\xe1\x64\x60\x29\xc8\xbe\x02\xd3\xdf\xa3\x46\x3c\x02\x49\x2f\xe2\x72\xeb\xcb\x14\xe4\xe8\x1c\xa8\x66\x26\xc5\x0f\x58\xb5\xc0", 94, { 0xd9, 0xfe, 0x37, 0x6d, 0x62, 0xbb, 0xe6, 0xf9, 0x22, 0xe8, 0xd4, 0xc7, 0x9c, 0xa1, 0x40, 0x3c }, { 0xb9, 0x96, 0x50, 0x6e, 0x38, 0x1b, 0xbe, 0xe5, 0x0a, 0xa2, 0xd7, 0x51, 0x1d, 0x75, 0x20, 0x63 } },
{ "\x7b\xcb\x0a\x7c\xbf\xa6\x51\x24\x0b\x54\x01\xa7\x56\x17\x73\xcf\xfd\x08\x85\x58\x76\x8c\x90\x48\x6e\x82\x53\xbc\x51\xf0\x88\x9a\x24\x73\xb9\xd2\x9d\xf9\x14\x61\x6e\x6f\xd9\xc3\x17\x80\xfa\xb0\x2a\x2f\xcb\xee\x49\xca\xfd\x91\x7b\xfa\xe1\x05\xab\x6a\x54\x4a\x7e\x37\xe9\x8d\x33\xfd\xe6\xf1\x05\x0a\x37\x51\xdc\x31\xcc\x5b\xed\xb8\x22\x18\xa8\xe3\x30\x44\xf1\x5e\x9e\xcb\xba\x30\x16", 95, { 0x64, 0xcd, 0xf0, 0x1a, 0x85, 0x0c, 0xf9, 0x7f, 0x1d, 0xba, 0x02, 0xc7, 0x1e, 0x4e, 0x7c, 0x1b }, { 0x69, 0xae, 0x3e, 0x4e, 0xd8, 0x5e, 0x92, 0x15, 0xef, 0x58, 0xec, 0xeb, 0x92, 0xe7, 0x3c, 0x56 } },
{ "\x29\x40\x47\xbb\xd6\xc4\x11\xe5\x58\xbf\x4e\xad\x30\x89\x8e\x7e\x02\xea\x27\x6d\xc9\x41\x2f\x9e\x9b\x8b\x3c\x63\xbd\xcf\xd8\x5e\x06\x9e\x59\xf5\x22\x65\x5a\x89\x0e\x01\xc8\x1f\xc4\x96\xb3\x32\xe6\x6e\x98\x63\x66\x4f\xbc\x0d\x50\x3c\xd2\x53\x9e\x20\x20\xc3\xe2\x94\xf7\xe0\xa6\x88\x55\x04\xdb\x2e\x7d\x32\x3d\x3c\x7f\x37\x40\xc4\x15\x82\xe2\xe5\x33\xd5\x6c\xea\x82\xc6\xc9\x42\xc5\x8b", 96, { 0x30, 0x48, 0xaa, 0x96, 0xcc, 0x94, 0xb9, 0xf3, 0x87, 0x11, 0xfa, 0x34, 0x6b, 0x2b, 0xd5, 0x48 }, { 0x8f, 0xbe, 0xd5, 0xa6, 0x68, 0xef, 0xdb, 0xd9, 0x3d, 0xda, 0x4b, 0x98, 0x97, 0x7a, 0xb9, 0x30 } },
{ "\x0a\x1f\x5b\x83\x81\x2b\x27\xfd\x06\x8e\x64\xe3\x69\x8e\x93\x31\x43\xfb\x3e\x75\x62\x4e\x12\xde\xf8\xe0\x64\x4e\xcc\x8e\xbf\x99\x06\x8f\x84\x8e\xaa\x90\xfb\x22\xa6\x7c\xfd\x75\x6b\x92\xf2\x31\x7e\x6a\x84\x0c\x5f\xca\xf9\x4b\x79\x7b\x48\xdc\x3d\x22\x5a\x7d\x0e\x85\x3a\xa4\x52\xe8\xce\xce\x16\x61\x06\xae\xe7\x4d\x12\x39\x28\x1b\xbc\xb0\xd3\x9e\xea\xb7\xcf\xc5\x34\xb1\xf3\x24\x1f\x43\x0d", 97, { 0xe5, 0x50, 0x67, 0x79, 0xd1, 0xbc, 0xa0, 0xf8, 0x1a, 0x7f, 0xdc, 0xda, 0x55, 0xa3, 0xc0, 0x71 }, { 0x75, 0xc6, 0x10, 0x5b, 0xba, 0xf1, 0xe7, 0xbd, 0x19, 0xd2, 0x6b, 0x1d, 0x04, 0x18, 0x68, 0x71 } },
{ "\xd0\xd9\xf9\xdb\x50\xaf\xe1\x44\xd3\x11\xb7\xc4\xe9\xa4\x49\xbc\xd2\x34\x70\x2e\xbd\x20\xc3\xd8\x8d\xce\x7e\xc9\x3f\x84\x3c\x45\x2d\x6a\xc9\x63\x79\x37\xec\x08\xe2\x27\xda\xa6\x1c\x3a\xa7\x6a\x4e\x12\x91\xc4\xce\x3d\x21\x17\xc0\xc1\x8b\x11\x44\xbc\xc7\xc7\x04\x82\x91\x3b\x17\x02\x6a\x7b\x5e\x62\x8a\xb9\x76\x35\xb5\x41\x2d\x8c\x63\x55\xb9\x74\x79\xca\x59\xa7\xc5\xb3\x07\x40\xca\x7e\x10\x50", 98, { 0x22, 0x0e, 0x71, 0xf2, 0x7c, 0xf7, 0x8a, 0x76, 0xe9, 0xc8, 0xc2, 0xbf, 0x02, 0x49, 0xf0, 0xf3 }, { 0xd0, 0x5e, 0x7c, 0x8a, 0x27, 0x8d, 0x94, 0x35, 0x3d, 0x11, 0xbb, 0xd2, 0x94, 0x3f, 0x91, 0xa8 } },
{ "\x62\x5b\xe8\x7d\xa7\x7a\xa7\xb6\x86\x65\x64\x11\x0e\x19\xa1\x05\x02\x60\x2b\x24\x6c\xa5\x26\x73\x42\x7a\x89\x76\xf9\x88\xb8\xa2\x2a\x0b\xa3\xb7\x39\x89\x9a\x25\x16\xeb\xec\xe1\x7e\x0c\x28\x81\x22\x56\xa8\x88\xcb\x7f\x75\x9f\x2f\xfd\xda\xfb\x46\xfe\x4f\x14\x18\x47\x7a\xc5\x90\x2d\x3f\x9c\xd7\x45\xd6\xc1\xae\x90\x14\x5d\xe9\xf4\xe5\xdd\x59\xd2\xca\xf9\x53\x6b\xb4\x49\xc3\x35\x87\xcf\x94\x71\xf0", 99, { 0xea, 0x58, 0x32, 0xd8, 0x93, 0x3c, 0x75, 0x65, 0x02, 0xa8, 0x33, 0x6d, 0x07, 0xfc, 0x91, 0x04 }, { 0xa3, 0xc5, 0xd2, 0xb0, 0xc3, 0x48, 0x60, 0xb0, 0xc3, 0xa8, 0x17, 0x9a, 0x8b, 0x4d, 0x78, 0xa6 } },
{ "\xf5\x89\x34\x2f\xa8\xb7\xc7\x9b\x9c\x1f\x63\x9d\xc7\xe8\xe3\xbc\x34\x07\x5f\x3f\xe9\x6b\x90\x3d\xb1\x08\x9a\xc1\xf9\x77\x97\xcc\xde\x58\x06\x12\xb4\xc3\xd1\xef\x1c\xa9\x94\xd7\x36\xe9\x50\x75\x71\x10\xc7\x1d\x99\x47\x86\x6e\xb6\xf9\x35\xf6\x4c\x3f\xb2\x5f\xd6\x9d\x07\x26\x38\xc4\x5d\xbb\x20\x8e\x83\x1c\xd8\xd6\x38\x24\x04\xac\xc8\x4c\xbf\x8c\xf0\x91\xb1\x55\xd9\xd9\x14\x6c\x44\xc0\xc7\x56\x19\xff", 100, { 0xfc, 0xe1, 0x98, 0xbf, 0xd7, 0x5a, 0x35, 0x20, 0xca, 0xdf, 0x53, 0x28, 0x03, 0xec, 0x3d, 0xeb }, { 0x4b, 0xc9, 0x36, 0x41, 0x6f, 0xfe, 0x90, 0x20, 0x09, 0x5e, 0x5e, 0x46, 0x07, 0xd0, 0xea, 0x33 } },
{ "\xc0\x8e\x50\xb1\xcd\x45\xb2\xe9\x00\xbc\x60\x73\x31\xe3\x03\x2e\x49\xa2\x23\xf8\xf2\x01\xbd\x00\x3a\x67\xb2\xd5\x99\xbf\x4f\xdd\x96\x38\x51\xd4\x6c\x56\xbd\x7e\x72\x00\x34\x3c\x61\xa6\xb9\xa0\x28\x94\xfd\x56\x78\xb2\x41\x8e\xe8\x9e\x33\x3c\x7d\xfc\xe5\x99\x1b\x78\x15\x29\xb0\x77\x0b\x9f\x3c\x0d\x77\x8d\xc5\x13\x16\x1a\xeb\x5a\x5d\x4e\x4f\x83\x36\xfc\xd5\xb8\x3f\x82\x2a\xbe\xee\x4c\xa2\xf4\xa5\xfd\x37", 101, { 0x9a, 0x5d, 0xb1, 0xd8, 0xed, 0x62, 0x9a, 0x10, 0x80, 0x56, 0x14, 0x1d, 0x2b, 0xb9, 0x3c, 0xed }, { 0xbb, 0xb5, 0x5f, 0xd1, 0x5e, 0xa7, 0x5a, 0xdc, 0x4e, 0x0c, 0x5d, 0xa0, 0x76, 0x32, 0x1a, 0xe1 } },
{ "\x5b\x00\x12\x98\x06\x8d\x02\x3e\x66\x62\xb9\x48\xaf\x0d\xa5\xd8\x8b\x63\xc9\xa1\x68\xaa\x1b\xe3\x25\x5c\x63\xf2\x64\x65\x7a\x0c\x95\xcd\x08\x37\xf8\xc6\xcd\x43\xde\x80\xaa\x68\x74\xae\x5a\x8f\x31\x67\xc8\x07\x88\x79\x2e\x46\x9d\xb9\x08\x6f\xd2\x2c\xd5\x4e\x29\xe4\x67\x98\x6d\x80\xac\xa1\xa3\x70\x2b\xf6\x46\xd1\x12\xc3\xd0\x22\x50\xb2\x33\x7f\x5c\xba\x1c\xb3\x7f\x52\xe4\x38\x82\x92\x3c\xfc\x20\xf2\x62\x08", 102, { 0x2a, 0xc6, 0xe7, 0xae, 0x6f, 0x11, 0xfd, 0xde, 0x0e, 0xb9, 0x30, 0x50, 0xc1, 0x92, 0x65, 0xaa }, { 0x5d, 0x90, 0x7e, 0x73, 0x13, 0x3b, 0x2d, 0x5e, 0xbc, 0xcf, 0x19, 0x69, 0xf8, 0x8b, 0x58, 0x60 } },
{ "\x05\xd4\xc4\x19\x7c\xc7\x01\xb7\xd0\x9e\x3c\x89\xe7\x3d\xcd\xda\x3f\xb7\xc2\x9e\x9c\x6f\x19\x10\x2a\x8e\xb3\xcd\x0b\x67\x57\xe5\x3a\x45\x8d\x35\xa6\x74\x74\x64\xb9\xb3\x23\x56\xf9\x20\x47\x1c\xac\x67\x75\x03\xc2\x93\x5e\x23\x16\x88\x3a\x83\x9f\xaf\x81\xd5\x5c\xf5\x91\x9d\xe5\xa7\x49\xe6\xf0\x8d\x8d\xf8\x61\x51\x68\x1f\xfa\x64\x49\xa5\xf2\xa8\xb0\xdf\x82\xfa\x19\x7c\xd4\x75\x1f\x12\x91\x47\x74\xd8\x9e\x0b\x57", 103, { 0x9e, 0x7d, 0xd4, 0x07, 0xa6, 0xf4, 0xcc, 0x5c, 0x39, 0x2a, 0x68, 0x68, 0x5e, 0x83, 0xc5, 0x40 }, { 0x46, 0x4e, 0x89, 0x61, 0x33, 0x28, 0x45, 0x8b, 0x64, 0x6a, 0xa6, 0x77, 0xf6, 0xf4, 0xea, 0xf6 } },
{ "\x64\x1a\xc1\x67\x59\x18\xbc\x5f\xd6\x16\x3b\xa8\x1d\x2f\xac\x8d\x07\x34\x5d\x20\xc7\x47\x59\x98\x7e\x94\xec\x8a\x73\x29\xeb\x75\x30\xaf\xa2\xa3\xa5\xf6\xb1\xc6\x16\xfb\x2a\xba\x0d\xa2\xb2\x84\x12\x43\x81\x1e\x51\xa5\x54\x5b\x29\x9f\x95\x87\xf4\x27\xa0\xce\x3d\xb9\x37\x00\x3b\x78\x70\x47\x2a\xb2\x1c\xe4\x83\x7b\xa6\xae\x48\x7e\x97\x14\xb3\x88\x98\x63\x0c\xf5\xd5\x77\xf8\xfb\x8f\x33\x77\x17\xcb\x82\xdb\x01\x59\xd4", 104, { 0x70, 0x4a, 0x67, 0x68, 0x01, 0x8f, 0x56, 0xdc, 0x1e, 0x7c, 0xef, 0x98, 0x5b, 0x0d, 0x0c, 0x94 }, { 0x7d, 0x17, 0xb3, 0x9b, 0x7b, 0x77, 0xe6, 0x41, 0x70, 0x46, 0x6b, 0xdf, 0x21, 0xdf, 0x7d, 0x4e } },
{ "\x75\xce\x19\x27\xfb\xe0\x1c\x44\x6a\x45\x4a\x15\x22\x1d\x93\xb0\x67\x56\x18\x18\x12\x28\x60\x9a\x87\x5e\x12\x76\xe3\x7e\x0a\xb6\xac\x34\x45\x97\xe9\x28\xcc\xa7\x40\x4a\x16\x33\xae\x20\x2a\x8e\xc1\x6a\xd2\x57\x94\x5f\x99\xf4\xf2\xe9\x67\x24\xa1\xbf\x15\x11\x4e\x39\x05\x7f\xc7\xe1\x83\x9c\x5d\xe8\x86\xac\x48\x88\x30\x13\x25\xd8\x2b\x15\x1f\x0f\xa3\x9b\xb8\x83\x3d\xbc\xb2\xe6\x72\xdf\x32\x24\x01\x8e\x1d\x4b\x9e\x8a\x32", 105, { 0xb4, 0xcb, 0x6d, 0x6b, 0x31, 0x3b, 0x0a, 0x3e, 0xc4, 0x44, 0xaa, 0x1d, 0x47, 0x60, 0xdd, 0x6f }, { 0xe9, 0x84, 0xcc, 0x0a, 0xb9, 0x41, 0x7c, 0xaf, 0x19, 0x33, 0xf8, 0xcb, 0x82, 0xf1, 0x2f, 0x88 } },
{ "\x4c\xa8\xec\xde\x53\xc1\x8e\x97\xf0\x8a\x20\x5d\x08\x49\x49\x61\x58\x3f\x51\xa8\x2a\x03\xef\xb2\x1d\x9d\xba\xf0\x71\x05\x94\xc1\xf9\x53\x65\x8d\xe4\xa3\xb2\x26\xa8\xe0\xe5\x53\x52\xa2\x35\xc2\x4b\xd9\xac\x81\x14\x3d\x2f\x1a\x40\x27\xcf\x68\x38\xea\xda\xf9\x75\x1b\xdf\x12\x7c\x12\x59\x02\xe1\x5f\x38\x3d\x59\xbf\x89\x6d\xb5\xdb\x88\xf0\x2e\x22\x8d\x52\x0a\x0e\x10\x1d\x6b\x12\x6a\x59\xe7\xbf\x29\x40\xc7\x07\x10\x86\xda\x6c", 106, { 0xe5, 0x0b, 0x80, 0x3e, 0x9d, 0x6c, 0x8f, 0xd4, 0x7a, 0xb2, 0x7f, 0xa7, 0xc4, 0xa6, 0xaf, 0xf0 }, { 0xdb, 0xfe, 0xc5, 0x92, 0x9c, 0x3d, 0x57, 0x37, 0x1e, 0x96, 0x69, 0xd8, 0xc9, 0x88, 0xae, 0x85 } },
{ "\x0b\x05\x75\x1e\xdf\x8e\x11\x5e\x96\x92\xe8\xd3\x3f\x21\x80\x89\xb4\xad\x32\xb8\x6e\x49\xf3\xb3\x1f\xd7\x45\xd9\xfb\x95\x3b\xea\x31\xa8\xfd\x36\xa9\x9b\x7d\x91\xd0\xea\xdc\x7a\x24\x88\x79\xa4\xce\xb4\x6e\x40\xea\x5c\xce\x27\x4f\x36\xd6\xe0\x7a\x3f\xdd\x87\x7d\xaf\x2a\x6d\xc4\xe7\x11\xdf\xb7\x2f\x20\x6e\xa2\x65\x61\x64\xb4\x29\x0d\xc5\xdc\x1c\xf6\xa6\xbf\x5b\xff\xe1\xb8\xea\xf8\xee\x5f\x92\x1a\x9d\x1f\xda\xe4\xec\x14\x75\x46", 107, { 0xac, 0x6d, 0x0f, 0xbb, 0x31, 0x09, 0xbd, 0x86, 0xc8, 0xdb, 0x71, 0xc2, 0x4c, 0xf8, 0xd4, 0x2d }, { 0x33, 0x1e, 0x6e, 0x74, 0xf6, 0x5d, 0x75, 0x94, 0xdf, 0xf7, 0x13, 0x50, 0x6e, 0x8e, 0x3e, 0x66 } },
{ "\x2f\x3f\xfa\x63\x4e\x0d\x7e\xf6\xfd\x46\x85\x50\xd8\xf1\x3c\xdb\x8c\x6a\x68\x94\x61\x08\x3e\xbe\x72\xaa\xe9\x2b\x16\xda\xf7\x92\x03\x4d\x38\x74\x33\x40\x59\x52\xfc\x9b\x61\x09\xa8\x73\xd3\x2a\x6a\xe2\x21\xb0\xa0\x9d\xa7\xe9\xd7\xf4\xd0\x83\xd8\x6b\x3b\x10\xbf\x63\x79\xd8\x1b\xce\x85\x60\x42\xa4\x25\x49\x35\xd5\xa3\x31\x0d\x38\xa1\xb9\xfb\x3c\xce\x55\x5e\x61\x4c\xf0\xb9\x2d\xcd\x82\xb9\x61\x09\xb5\xf5\x24\x18\xd6\xd4\xc3\xaf\xdb", 108, { 0x80, 0x6f, 0x88, 0xae, 0xd3, 0xc4, 0x0b, 0xee, 0xea, 0x85, 0xb8, 0xb2, 0x4e, 0x17, 0xef, 0x5e }, { 0x97, 0xc1, 0x12, 0x6e, 0x5e, 0x39, 0x63, 0xdd, 0x6f, 0x3e, 0x50, 0x6f, 0x9b, 0x2a, 0x63, 0xb2 } },
{ "\x29\x48\x9a\x67\x6e\x1c\xa7\xb9\xf8\x5b\xba\xbd\xf8\x80\x65\xa2\x95\xfc\xd5\x43\x52\xb3\xdc\xc5\xb4\xc0\x4a\x5a\x2c\xae\x35\x54\x59\x75\x45\xc4\xa2\xd1\x18\xb8\x70\x54\x71\xcc\x71\xee\x2d\x4e\x13\xe8\x44\x7b\xd5\x4c\x3c\x04\xb6\x86\xfa\x63\xe7\x89\x8d\x31\xc3\xae\xde\x56\xad\x10\xef\x6e\x2b\x0e\x90\xbf\xcb\x02\x4d\xfd\x28\x1f\xe0\x82\xef\x67\x30\x35\xb5\x75\x4d\xf1\xd5\x27\xeb\x34\x98\x31\x26\x4d\xf2\xd2\xc5\x91\x72\xe2\x22\xc3\x3f", 109, { 0xd6, 0x48, 0x7e, 0xb3, 0x90, 0xe3, 0x9c, 0x12, 0x03, 0xf5, 0x8a, 0xa7, 0x83, 0x46, 0xe3, 0x6e }, { 0x28, 0x20, 0x27, 0xad, 0xd9, 0x50, 0x46, 0x18, 0x87, 0x63, 0xbf, 0x4a, 0x6a, 0xc1, 0xeb, 0x57 } },
{ "\x58\xdb\xa7\x08\xed\x0f\x20\x3d\x9e\x18\xe9\xd3\x9b\xe9\xa6\x18\x6a\xe9\x28\x28\x7d\x67\x3f\x21\x52\x46\xb5\xec\xae\x1e\xd3\x34\xa3\xf0\xe5\x62\xb1\x5e\xda\xd5\x7e\x62\x4c\x0f\x82\xc7\x13\x9b\x00\xee\x9a\x59\xcb\x47\xd7\x9e\x7f\x3e\xa1\x53\x99\x26\x97\x2a\xfa\xd8\xe3\x04\x3c\x5c\xe8\x77\xdf\xb0\x6c\xfb\x64\x2b\x70\x64\x1e\xb4\x86\xcd\x90\x60\x0b\x56\xdf\x67\x70\xc9\x90\xfd\x65\x5b\x9a\xc1\xd6\x97\x2a\x84\x1c\x30\x9f\xb3\x7c\x99\xa2\xfd", 110, { 0x93, 0xf2, 0x48, 0x67, 0x60, 0x1d, 0x5c, 0x64, 0x9f, 0x7d, 0x4a, 0x89, 0xd9, 0x75, 0xad, 0x4e }, { 0x58, 0x61, 0xdd, 0xd0, 0xdd, 0x12, 0x1a, 0x39, 0x17, 0x2e, 0x26, 0xb4, 0x79, 0xda, 0x11, 0x2f } },
{ "\x0e\x35\x9a\xdd\xbe\xf9\xd1\x44\x5c\x35\x30\x35\xd1\x20\x7e\x3a\xa8\x15\xef\x8f\x03\xab\x64\x28\xdc\x36\x94\x8f\xc4\x67\x06\x8b\x73\x39\x73\x4f\x71\x0d\x26\x26\x46\xa0\x6b\x63\x5e\xac\x37\xa8\x95\x77\x9f\x8a\xd9\xcf\x06\x4d\x7a\xb9\xf8\x0f\x81\x9b\x69\xe7\x2a\x16\x75\x40\xda\xac\x31\xa3\x89\xb7\x19\xf2\xf9\x5c\x7a\xb1\x80\xb9\x1f\x06\x0a\x47\xb0\x99\x8d\xf9\x13\xd5\x9a\x55\xc3\x2f\xaa\x7f\x10\xbd\x4a\x0f\x7a\x1e\x6d\x69\x66\x53\xa3\x41\x31", 111, { 0xa8, 0x9c, 0xc1, 0x1e, 0xe2, 0x0a, 0x6b, 0x9e, 0x13, 0x13, 0x78, 0x39, 0xff, 0xb1, 0x59, 0x70 }, { 0x92, 0x39, 0xa4, 0xa8, 0xc4, 0x02, 0x5a, 0x0e, 0x37, 0x56, 0x27, 0xe5, 0xe2, 0x5c, 0xbd, 0x7b } },
{ "\x39\x9b\x52\x70\x4f\x0e\xa7\x5b\xde\x3d\xe6\xfb\x38\xd0\xdf\xe4\xe4\xb4\xc6\x23\x09\x25\xb5\xb4\xc1\x8b\x71\x00\x5e\xc3\xdc\xc2\x26\x9d\xb3\xaa\x74\x0c\x5e\x8f\xf0\x7a\x8d\xf2\x1b\x9a\x67\x85\xca\x37\xa1\x59\x23\x96\xec\x69\x57\x9f\x57\x86\x18\xa5\x4d\xc2\x43\x36\x0f\x1d\x7e\xd3\x23\x64\x01\x4d\xe4\xdb\xc7\x84\x76\xa4\xe4\x80\x7c\x5c\x5c\xd9\x1e\x80\x9c\xc4\x00\xc6\xa7\xa6\x43\x74\x15\xe0\x86\xc1\x5d\xbe\xf6\x30\x05\xab\x2f\xfe\xe4\xf4\x2c\x74", 112, { 0x9f, 0xb3, 0xba, 0xeb, 0x69, 0xce, 0x2b, 0xde, 0x17, 0x88, 0xde, 0xc3, 0x27, 0x61, 0x5c, 0x20 }, { 0xb1, 0x9e, 0x03, 0x92, 0x62, 0x5a, 0xfb, 0x4c, 0x5d, 0xdf, 0x87, 0xdf, 0xbf, 0x80, 0x75, 0xa4 } },
{ "\x03\x6a\xd1\x9d\x50\x43\xa7\x88\xc0\xcd\xdd\x3c\xe9\x4f\x63\x53\x9c\xc2\xce\x59\x8d\x38\xf9\x63\x16\x3b\x5a\x86\x82\x1d\x36\xd1\xc2\xc7\x34\x43\xe2\xcd\x35\x7e\x8b\x7a\x96\xa3\xe5\x22\x56\xfd\xde\x0f\xa1\x62\xed\xc8\x95\xd1\x4e\x10\xa6\xee\xa6\x4a\x5c\x52\x13\xdd\x50\xb5\xc9\xad\xe1\xfd\xa7\xb8\xdd\x46\x2d\x33\x40\x43\x8e\x52\x28\xc9\x61\x97\x60\xe4\xe8\x5e\x36\xcc\xa4\xe6\x26\x7f\x2f\xd0\x98\x69\xd8\x32\x84\xa8\xd0\xc0\x8f\x22\xab\x57\x85\xb4\x8d", 113, { 0x47, 0x3a, 0x23, 0x8e, 0x1b, 0x64, 0x93, 0x2a, 0xd4, 0x2c, 0x75, 0xba, 0x78, 0xb2, 0xe7, 0xcc }, { 0x29, 0x5b, 0xd3, 0x6b, 0x00, 0xc9, 0xc1, 0xf6, 0x63, 0xa7, 0xe0, 0x02, 0x05, 0x1d, 0xcd, 0x22 } },
{ "\xd5\x21\x09\x05\x28\xc3\x5e\xdf\xd4\x3c\x69\x3f\x02\x9b\x1d\x65\x92\x56\x33\xfa\x01\x25\x9c\x62\xe1\x0a\xdd\x41\xf6\xb8\x56\x7f\x4e\x01\x70\xb2\x21\x95\x3f\x9a\x1b\xe6\xfc\xd0\x56\x0f\x67\x2b\xfb\x2f\x46\xc6\xf6\x76\x6c\xdb\x89\x2c\xdb\x6f\x50\xbb\x45\x74\x9d\x3d\x56\x94\x5b\x46\xe0\xc3\x67\x37\xd5\xdb\x3b\xe6\x5f\xa9\xda\xa9\x5d\xcf\x5b\xc3\xa9\xb7\xba\xf4\xd2\x5c\x88\x25\x81\xa3\x4a\x76\x93\x73\x23\x2f\xad\xec\x56\x71\x75\x89\x3f\x72\xb1\x68\x10\xc7", 114, { 0x69, 0x94, 0x11, 0x43, 0x29, 0x54, 0xbd, 0x22, 0x6f, 0xf0, 0xd2, 0x35, 0x88, 0xc2, 0xa5, 0x6b }, { 0xaf, 0xeb, 0x63, 0xf1, 0x13, 0x34, 0x21, 0x15, 0x12, 0x03, 0x8a, 0x84, 0xb9, 0x15, 0x1c, 0xa4 } },
{ "\x59\x3d\x8d\x75\x6f\x9c\x96\xc1\x6d\xc7\x68\xa3\xae\x0f\xe1\x6d\x84\x3d\x3a\xb5\x74\x76\x77\xb1\xe3\x02\x67\x06\xa0\x82\x27\x2f\x5d\xe4\xac\x95\xd0\x03\xe2\x0e\xd1\x0a\xcd\xf6\x23\x34\xac\xfb\x66\x86\xac\xd9\xf8\x5a\x66\x80\x6f\xb8\x47\x70\x11\xeb\x7c\x3c\xe4\xa5\x7e\x41\x95\x50\x2e\xfe\x1a\xd4\x99\xe0\x25\x99\xb6\x7e\xae\x8f\x12\x8a\x40\xc5\x5b\xc4\x3f\xa2\x27\xe7\x4a\x67\x05\x01\x92\xb4\x2d\x3e\xf2\xb6\x35\x10\x27\x22\xb0\xe3\x0f\xba\x4e\xde\x84\xcc\x0f", 115, { 0x6a, 0x83, 0x99, 0xcb, 0x71, 0xb0, 0x54, 0xfd, 0xcb, 0x00, 0xd9, 0x26, 0xc3, 0x59, 0xe7, 0x19 }, { 0x4e, 0xb3, 0x47, 0x44, 0x0b, 0xae, 0x11, 0xc9, 0x55, 0x22, 0x53, 0x9c, 0x51, 0xa5, 0x68, 0x70 } },
{ "\x10\xac\x6f\xae\x54\x0d\x10\x94\x90\x98\x9a\x55\x44\xd6\xb7\x4e\x7f\x81\x0e\x41\x6d\x8a\x9c\x59\x64\x40\x6d\xbb\x0b\x0e\x16\x0b\xe1\xbf\xa9\x3c\xcc\xe6\x07\x1f\x89\x52\xb8\xbc\xd9\x97\x89\x8c\xaf\xb8\x1f\x2d\x0c\x88\x37\x5d\xa0\xb6\x1e\x4f\x05\xfe\x9f\x8b\x8a\x31\x77\x68\x74\x2b\x20\xe5\x27\x36\xab\x32\x59\x85\x48\xa5\x1e\x27\x41\xa9\xdb\x2a\x8a\xd0\xa2\x37\x24\x69\x9f\x7a\xb6\x3b\x13\x2a\x16\x3d\x69\x35\xe2\x17\x25\x6f\xdf\x09\x90\x94\xf6\x87\xee\xb6\xe5\xf1", 116, { 0x1f, 0x37, 0xab, 0x6f, 0x06, 0xc4, 0x09, 0x00, 0x59, 0xda, 0x2e, 0xd3, 0x01, 0xdc, 0x4d, 0x03 }, { 0x56, 0x40, 0xa8, 0xf8, 0x94, 0x6c, 0x82, 0x5b, 0xf4, 0x88, 0x16, 0xb8, 0x1a, 0x69, 0xce, 0x08 } },
{ "\xd8\x33\xce\x43\x0d\x50\x12\x77\x70\x53\x57\x1b\xba\x1c\xf0\x18\x07\x7d\x82\x9e\xe5\x0e\x84\x32\x61\xad\x3c\x92\x8d\x8b\x91\xfa\xa0\x65\x66\xfb\xa2\x73\xe8\x39\x69\x0a\xd7\xbf\x25\xda\x1c\x45\x6e\x09\x59\xb8\xf1\xb0\x9d\xc1\x45\x05\xe9\x57\x44\x64\x23\xbf\x99\x96\xa7\x78\xb7\x9b\xb3\x92\x5b\x4e\xac\xbd\x51\x87\xf4\x1d\xda\x2f\x2b\x06\xd5\x67\x9f\x9f\xcb\xf3\x31\xbc\x09\x05\xeb\x28\x53\x5f\x0e\x9a\xe8\xb5\x05\x41\x77\xbf\x55\x68\x7c\xe9\x18\xe8\x1f\xb9\x4c\x84\xf6", 117, { 0x6d, 0x09, 0xe8, 0x44, 0xe3, 0x0b, 0x04, 0xbd, 0xa3, 0x6d, 0x81, 0xd9, 0x2c, 0xa1, 0x9e, 0xe7 }, { 0xbe, 0xf4, 0x1c, 0x5f, 0x44, 0x51, 0xe4, 0xbb, 0x58, 0x65, 0x2a, 0x31, 0xc1, 0xa0, 0x9e, 0x7e } },
{ "\x93\xf8\x52\x5b\x1d\x29\xae\xc9\xe7\x21\x74\xfd\xf8\x46\x1e\x29\x88\x23\x45\x4f\xec\x37\x65\x34\xf9\x99\x14\xeb\x5f\x14\x16\x0e\x92\xc5\xa3\x7f\xf1\x0f\xa4\xdf\x68\x97\x28\x0a\x18\x95\xed\x77\x9d\x95\xb1\x81\xa5\x2c\xa9\x8b\xc8\xf1\xd4\x3d\xd4\xbd\xb9\x14\xbc\xfb\xbf\xde\x9a\x5c\x2a\xbf\x3c\xd4\x8f\xbd\x57\x12\xb6\xb0\x98\x0f\x7e\x76\x0f\xa5\xf5\x20\xfb\x43\x86\xe0\x66\xfd\xd6\x9c\x87\xcc\xf2\xa8\x2c\xe9\x8b\xab\x47\x00\xb1\x74\xa7\x2d\xfc\x1c\x5a\xd3\x7c\xfa\xf8\x49", 118, { 0x79, 0x5f, 0xf9, 0x75, 0x07, 0xd7, 0x82, 0x1d, 0x71, 0x57, 0x3d, 0x8d, 0x23, 0x99, 0x8c, 0xc5 }, { 0x86, 0x19, 0x0c, 0x98, 0x55, 0x16, 0x22, 0x4f, 0xc3, 0xf2, 0xc2, 0x04, 0xd6, 0x0a, 0xfe, 0x87 } },
{ "\x56\xd8\x73\x6c\xd6\xfd\x45\xcb\x7c\xd0\x2c\xa9\xb2\xfb\x59\x78\xb8\x95\xfd\x27\xdd\xdc\x7d\xef\x7a\xc1\x3e\xc8\x6d\xad\x0e\x17\x1f\x04\xd6\x31\xc4\x49\xc5\xc7\x86\xb3\x37\x78\xae\xce\x4f\x30\xe7\xde\x04\xdc\x22\x68\x95\x40\x67\x13\xe0\x01\x78\x81\x35\xe9\x44\xf2\x32\xb1\x9f\x9b\x4b\xc7\x30\x7f\x1b\x6e\xa4\x19\xf0\x90\x38\xa8\xea\x74\x2a\x7e\x68\x32\xb2\xe1\xd4\x0a\x55\x86\x49\x4f\xc6\xcc\x3c\x70\xbb\xb3\x2c\x99\x42\x1a\xd1\x62\x1f\x9c\x23\x1c\x88\x40\x40\xf8\x8f\xb8\x68", 119, { 0x63, 0xd9, 0x9f, 0xb8, 0x4e, 0x24, 0xf1, 0xf7, 0x82, 0x98, 0x25, 0x0f, 0x30, 0x24, 0xad, 0x24 }, { 0x76, 0x7e, 0x9b, 0xec, 0x29, 0xc5, 0x66, 0x49, 0x70, 0x69, 0xf6, 0xb5, 0x75, 0x5d, 0x2b, 0x3d } },
{ "\xc2\xd9\x4d\x7a\x19\xaa\x34\xb4\xeb\x7f\x96\x43\x01\xe9\xae\x45\xe6\xb6\x32\xd3\x35\xa1\x40\x77\x95\x15\xf0\x9a\x36\x7a\x69\x60\xa8\x25\xf5\x1f\x9b\x31\x44\xb5\x80\xf0\xae\x2a\x1f\x85\x9e\x2b\x2f\x85\x9a\x2f\x8f\x44\xa7\xe4\x28\xfb\x5a\x71\x04\x79\x65\xae\x9b\x19\x73\x66\x13\x5b\xe1\x8f\x12\x23\x33\xf2\x09\xf7\x7b\xe8\xcf\xd0\xe6\xd0\xad\xc9\x07\xd8\xf4\xc3\x74\x89\x76\x64\x5a\xd2\x01\xb6\x4d\xda\x15\x55\x10\xee\xcd\xa0\xb2\xe7\x3a\xd7\xba\xb4\xa5\x1e\xe8\x5e\xe6\xf4\x19\x6e", 120, { 0xd9, 0xdf, 0x12, 0x7f, 0xad, 0xc4, 0x9d, 0xc6, 0xe7, 0xd8, 0x1d, 0x1a, 0x3e, 0xe1, 0xb2, 0x5f }, { 0x55, 0x6c, 0x4d, 0xd8, 0x71, 0xb8, 0xd4, 0xfa, 0x23, 0x85, 0xd8, 0x7e, 0x5c, 0xac, 0x16, 0x83 } },
{ "\xab\x42\x55\x99\x58\xcf\xa6\x51\x1b\xd7\x33\x2a\xe2\xfb\x4b\xdf\x28\x1d\x8a\x7b\x51\x65\xfc\xe7\x9f\xe1\xdb\xd6\x2c\x3e\x3f\xb9\x5a\xcd\x23\x64\xc4\xf9\x03\xe6\x73\x4e\xa4\x7a\xb3\xe3\xdb\xb2\x81\xd7\x07\x01\x92\x00\x31\x07\x9e\xd2\xce\x98\x17\xd2\x3c\x31\x15\x91\xd8\x3a\x20\x12\xc3\x2f\x98\x08\x55\x78\xf4\xd7\xba\xe3\xae\x51\x4c\xf8\xf1\xf0\x5e\xe9\x26\xde\xef\x34\x39\x17\xbe\x8e\x15\x17\x13\x94\xa7\x20\xdf\x46\x3b\xfc\xb5\x00\x2a\x2a\x10\xc3\x7c\x62\x4a\xd4\x90\x5e\x5f\x84\x49", 121, { 0x43, 0x36, 0xdd, 0xbd, 0x7c, 0x06, 0xef, 0x65, 0x82, 0x85, 0x10, 0x8c, 0x4e, 0x57, 0x1c, 0x19 }, { 0xe1, 0x5c, 0xd9, 0xde, 0x61, 0x7a, 0xfa, 0xb3, 0x1e, 0x16, 0x01, 0x37, 0xb6, 0x1e, 0x8a, 0x9d } },
{ "\xa2\x63\xc8\x09\x93\xc0\xae\x16\xac\x3d\xe7\xa4\xfc\x58\x4d\x7a\x0e\x4f\xbf\xa7\x67\x60\xab\xcb\x5e\x80\x1d\x9b\x8b\x9f\x79\x9c\x9c\x18\xe0\x5f\x98\xd4\x32\xdb\xb2\x01\x0a\x2c\x97\xea\xf7\x6f\xfc\x16\xd4\x31\xaa\xa2\xce\xa1\x4e\xf1\x9f\x59\xb3\xf2\x94\x4f\x69\xc3\xa6\xf0\xe2\x8c\x59\xd5\x7c\x11\x07\xc4\xdd\x3c\x7e\x59\x19\x11\xfd\x39\xb7\xb3\xbb\xe8\x6e\xeb\xf9\x14\x25\x63\x24\xf8\x3c\x83\xe0\x41\xa5\xcc\xb5\xd4\x0a\x7e\xdf\xcf\x9e\xbe\xd0\x94\x6b\x02\xe2\x79\x94\xf8\x3b\x44\x16\xe3", 122, { 0xfc, 0x3d, 0x58, 0x08, 0x1e, 0x80, 0x0c, 0x10, 0xd9, 0xbf, 0x2d, 0x95, 0x37, 0x56, 0x5c, 0x35 }, { 0x1a, 0x20, 0x57, 0xfe, 0x0d, 0x3e, 0xdf, 0xbd, 0xb8, 0xa3, 0x65, 0xb0, 0x1a, 0x71, 0x8d, 0xd8 } },
{ "\x5f\x53\xa3\x98\x23\x6f\x33\x82\x53\x4e\xf9\x32\x97\x5f\x1a\x9b\x5a\x7c\xf8\xbf\xa8\xc9\x7d\xd3\xcd\xe1\x4d\x8e\xee\xfe\x14\x6d\x12\xbb\xa9\xf3\x99\x32\xf7\x94\x96\x78\x8b\x37\x7f\x52\xe1\x16\x68\xbf\x23\x2b\x7f\xf5\xa5\x6a\xa2\x41\xa9\xf5\xb8\x27\x3f\x2f\x4a\xf6\xfa\x11\x13\x4f\xbc\xeb\x64\x10\x3b\x08\x56\xd5\xcd\x9b\xd9\x8e\xed\xff\xbb\xed\x9b\xd1\xcb\x7c\xd6\x8a\xe8\x61\xa9\x8a\xfa\xf5\xa6\xe2\x09\x54\x5e\xea\xbe\xae\x98\x91\x15\x26\x46\xec\xda\x91\x5e\xfa\xa3\x21\x20\x99\x4d\x8d\xd0", 123, { 0x9a, 0x6b, 0x61, 0x0b, 0x22, 0x1e, 0x2f, 0x82, 0x76, 0xbc, 0x00, 0xa4, 0x9b, 0x51, 0x43, 0x67 }, { 0x91, 0xa4, 0x10, 0x5e, 0x11, 0xcd, 0xd2, 0x02, 0x09, 0x85, 0x3d, 0xab, 0x41, 0x44, 0x82, 0x51 } },
{ "\x74\x60\x2a\x03\x37\xb0\x7e\x63\x1f\x5f\xd0\x00\xba\xc3\x3d\xbd\x18\x35\xdf\x2e\x61\xc9\x5e\xf4\x38\x2f\x50\xfe\x1b\x1a\x00\xae\xaf\x3b\x2d\xab\xcd\xa1\x22\xe0\x14\x1e\xfb\x24\xb4\x83\x63\x09\xed\x35\x59\x0f\x8b\x65\x7f\xe7\xd5\x29\x6d\xde\xbd\x58\xaf\x1d\xe9\x43\x20\xd9\xc8\x07\xea\xb9\xe3\xfc\x51\x82\xda\x00\xb7\x2b\x96\x96\x34\x30\x43\x90\x3b\xf4\x50\x62\xe8\x59\x23\x5f\x30\x94\x49\x76\x88\x49\x61\xe6\x37\x10\xcf\x07\x20\x63\xcb\xa2\x41\x1e\xd7\xc7\x57\xcf\xe6\xa9\xc8\x90\x30\xf2\x75\xd9", 124, { 0xdf, 0x2b, 0xcc, 0x23, 0xbb, 0x55, 0xc3, 0xa9, 0x35, 0x82, 0xb9, 0xb4, 0x4f, 0x33, 0x4c, 0x05 }, { 0x49, 0x19, 0x98, 0x2f, 0x02, 0x6d, 0x44, 0x96, 0x58, 0x36, 0xea, 0x2e, 0xf7, 0x61, 0x15, 0x2d } },
{ "\x10\xdb\x6e\xd4\x76\x36\x79\xac\x84\xe6\xa9\x97\xda\xe7\x07\xba\xca\xdb\xb3\x44\x11\x95\xd9\xc2\xe7\x35\x29\x8a\x99\x9b\xd4\xad\x50\xf0\xe0\x54\x52\x55\xa7\xbe\x20\x07\xc7\xc3\xb4\x0a\xd6\x22\xd1\xe3\x90\x89\x2e\x53\x7d\x44\xf7\xed\x97\x3b\xdc\x9d\xa6\x09\xcc\x85\x83\x05\x88\xf8\x36\xdb\x3c\xe2\xb5\x46\x73\x60\x17\x32\xb1\x1d\x3c\x45\xfc\x18\x6d\x42\x49\x99\x25\xea\xea\x4b\x93\x2b\x84\x2c\xff\x8f\xed\x76\xda\x84\x3e\x1f\x67\x77\x9f\xfe\x3c\x94\xc9\x72\xb5\xa3\xf9\x70\x19\x87\x8a\x12\x27\xbf\x6f", 125, { 0xce, 0x90, 0x30, 0xa3, 0x5c, 0xd8, 0x7a, 0xbc, 0xbe, 0xf4, 0x6c, 0x3c, 0xc9, 0xd6, 0x9a, 0x61 }, { 0x11, 0x37, 0x59, 0xe9, 0x61, 0x06, 0xf5, 0x1c, 0x05, 0x74, 0xdc, 0x06, 0x96, 0x74, 0xa7, 0x04 } },
{ "\x5a\x80\x37\x50\x9d\xed\xcb\x6f\x96\x2f\x63\xe6\xd1\x91\xa6\x43\x46\x4d\xbc\xa9\x30\x9a\xb5\x53\x5b\x9d\x7f\x5a\xe9\x3b\x16\x23\x40\x6d\xdc\x2e\x6b\x0f\xbb\x80\xb2\x73\x4e\x46\x32\x7d\x3c\x4d\x62\x9b\xe7\x11\x03\x1b\xa0\xb7\xcd\xe5\xfa\xcc\x48\x0e\x08\x42\x61\x39\x98\x61\xf8\x11\x24\xac\x58\x13\x45\xd7\x58\xb0\xf4\xa3\x5f\x8a\x93\x9d\xd7\x54\x67\x08\x41\xcf\xa0\xa3\x91\x0e\x41\x34\xdf\x80\x92\x7a\x83\x9d\x45\x6c\x6d\x5c\x08\xa2\x7d\x85\xa8\x5c\xb7\x51\x7a\xe1\xef\x53\x8e\x2d\x21\x0d\x06\xaa\x27\x4a", 126, { 0xfd, 0x16, 0x55, 0xb2, 0x2f, 0xd1, 0x51, 0xac, 0xaa, 0x30, 0xda, 0xda, 0xea, 0xac, 0xd0, 0x2e }, { 0x6f, 0x84, 0x7a, 0x82, 0xcb, 0xb8, 0xba, 0x73, 0x12, 0xbf, 0x29, 0x2e, 0x9c, 0x06, 0x2e, 0x7c } },
{ "\x55\xe9\x77\x03\x8b\x23\xa5\x18\x9a\x92\x28\x05\xf9\xf9\x4e\xea\x0f\xf9\x25\xcc\x60\x7a\xf5\xcf\x4f\x55\xc4\x2d\xeb\xb8\x28\x54\xbc\x20\xeb\xd1\xf9\x4a\xa7\x20\xfa\x7b\x3e\xf0\x2c\x72\x5e\x68\xed\x05\x8b\x90\xfe\xf5\xb9\x66\xc6\xcc\x06\xb8\xcc\xc7\xb4\x94\xab\xb9\x50\xb6\x2c\xc8\xac\x21\x8a\xca\xd6\x4d\x52\x15\x51\x72\xe5\x69\xdb\xf7\x50\x48\x42\x72\x37\xf7\x35\x70\xe1\xba\x45\xa5\x4d\xd5\x77\x00\x00\x9b\x68\x80\x65\x72\xaa\x18\x5d\x5b\xff\x5a\xa0\xd2\x38\xd0\x0c\xc0\x47\x80\xca\xf8\x29\x32\x07\x23\x5f", 127, { 0x39, 0x71, 0xc6, 0x33, 0xb0, 0x45, 0x1e, 0x12, 0xa1, 0x52, 0x61, 0xa6, 0x2a, 0xaf, 0x58, 0x93 }, { 0x7c, 0x91, 0x0f, 0x3c, 0x53, 0x7b, 0x19, 0xea, 0xae, 0x21, 0x6d, 0x00, 0x13, 0x6e, 0x3b, 0xab } },
{ "\xa3\xf5\xa1\xce\xe9\xfd\x5e\xe0\x8d\xe6\x35\x6b\xbb\x70\x62\x5f\x1e\xbd\xf9\x2e\x5b\xcf\x45\x3e\xff\x82\xa4\x14\x73\x98\x45\x9d\x6f\xce\x59\x88\xfc\x39\x55\xba\x35\x9c\x6a\xa1\x16\xab\x13\x24\xa6\x58\x6b\x76\x0b\xb6\xec\x9d\xe5\x92\x92\x65\x08\x8c\x90\xff\x2c\x2f\xcd\xd5\x0e\xe1\xec\x9b\xb2\xb2\x90\x5e\x51\xf8\x8e\x00\x04\x17\xa9\x37\xa0\x3e\x87\xbf\x7d\x86\x6e\xcf\x66\x9d\x5c\x90\x7b\xe1\xc5\x73\x4d\xfc\x74\x96\x2f\xaf\x8c\x20\x75\x22\x47\x08\x61\x43\xbc\x6a\x54\xbd\xc7\x86\xa9\x0e\xf8\x7a\x61\x19\xb7\x66", 128, { 0x8a, 0x7d, 0x5d, 0x66, 0x07, 0xfb, 0xc4, 0xea, 0x2c, 0x2c, 0xa8, 0xc0, 0x69, 0x7d, 0xa9, 0xbd }, { 0x49, 0x97, 0xa1, 0x19, 0x35, 0x9e, 0xdf, 0xe6, 0xbc, 0x53, 0xd0, 0x2a, 0x60, 0xd7, 0xba, 0xb9 } },
{ "\x44\xe5\xf8\x47\x1a\x98\xdf\xdf\x0a\x3a\x7f\xc7\xac\x19\x0d\x03\x6d\xa9\x41\x0b\x5e\x8b\xed\x5f\xa5\xb0\xa3\x6f\x30\x2d\xb3\x87\x83\xe1\xf8\x6d\x82\x9a\x8a\xb5\x7c\xaf\x78\xe7\x91\x4c\x78\x75\x70\x86\xa0\x27\x49\x47\x05\x0f\x6e\x1a\x11\x4b\x5b\x40\x83\x59\x91\x90\x93\x64\xb0\x1a\x22\x45\x2d\xb1\x43\xaa\x96\x68\x51\xc1\x5b\x2d\x1d\x33\x1e\x3f\x14\xfb\xa9\xd2\x0f\x8a\x9b\x24\xcd\x8e\x4a\xc4\xb6\x68\x2c\x1a\xb4\xaf\xe3\x06\xd4\xbf\x2b\x49\xb9\x7f\x7a\x00\x54\xcf\x44\x58\xa3\xf2\x3c\xa7\xa1\x30\xb7\x44\xd6\x0e\xcc", 129, { 0x53, 0x0b, 0xa3, 0x3a, 0xd8, 0xcc, 0x11, 0xed, 0x72, 0x34, 0x83, 0x31, 0xa5, 0xea, 0x10, 0x7b }, { 0x81, 0xbc, 0x8f, 0xcb, 0xe4, 0xcd, 0xbb, 0x30, 0xcc, 0xa1, 0xce, 0x87, 0x23, 0xc3, 0xde, 0x81 } },
{ "\x26\xde\xfb\xfa\x22\x5c\x5a\x0c\x77\x3a\xd5\xd7\xde\x33\x5b\x82\x2a\x03\xac\x06\x33\xff\x17\x11\x22\x8e\xe7\x6d\xfc\x80\x5c\x1b\x0d\x25\x52\x02\x48\x48\x32\x79\xfb\xa6\xec\x63\x79\xba\xb5\x4b\x43\xb8\x6d\xc0\x2d\x7d\x97\x1c\x8c\xcb\x12\xd6\x01\x14\x65\xfb\x2f\x50\xac\xe2\xff\x1d\x0d\xa2\x12\x57\x88\xf9\xa4\x75\x38\xfe\x36\x8b\x4f\x53\x99\x53\xfc\x6b\xb3\x54\x3b\xa1\x95\xc8\xc3\x5a\x93\xdd\x99\xb2\x68\x4f\x92\x87\x00\x32\xa9\x36\x82\xed\x05\xb1\x11\xa4\x6d\xf7\xf5\xd3\xe3\x4c\xc6\x3e\xe5\xb1\xa6\x50\x38\x2a\x46\x8b", 130, { 0x29, 0xb3, 0xfb, 0x3d, 0x8d, 0x55, 0x4c, 0xb8, 0xac, 0x4f, 0xc2, 0x19, 0xdb, 0xd7, 0x76, 0xf1 }, { 0xee, 0x66, 0x51, 0x82, 0xac, 0xe7, 0xc0, 0x2a, 0x2a, 0xab, 0x45, 0xed, 0x7d, 0x46, 0xe6, 0x78 } },
{ "\xeb\x67\x26\x05\x90\x52\x36\xe1\xc6\x76\x91\xef\x5c\x0d\x08\x76\x52\x18\xe4\xe4\x36\x1d\x88\xfe\x1c\xac\x97\x1e\x1e\xf8\xfb\x39\x94\x8c\x53\xbd\x96\xad\xc1\x13\xf7\xdf\x92\xcd\xaf\xd3\x47\xd8\xa5\xe0\x4c\x53\xf6\x8b\xbf\xcc\xb5\x7e\xab\xf8\x5d\xb6\x42\x8f\x82\x28\xe8\x80\x55\xf8\xbb\x01\xda\x15\x8c\xf8\x58\x39\x45\xce\x67\x6b\xa0\x64\x4b\xc4\x2b\x38\xde\x3e\x08\xb3\x5b\x6b\xc3\x38\xf9\x67\xe8\x31\x20\xa6\xcb\xa6\x10\x61\x2b\xa2\xf1\x4e\x42\x9b\x32\x02\xb6\x3a\x81\x55\x94\x44\xc5\x6c\xe1\x86\x45\x2a\xae\xc5\x4a\x4b\x93", 131, { 0xbc, 0x4f, 0xb5, 0xed, 0xec, 0x45, 0x3e, 0xec, 0xe3, 0x4a, 0x6a, 0x75, 0x92, 0xd9, 0x8e, 0x95 }, { 0xf5, 0x4f, 0xd4, 0x4c, 0xc0, 0xc0, 0x1b, 0xf4, 0xa4, 0x56, 0x81, 0xc2, 0xbc, 0x8b, 0xd3, 0x7b } },
{ "\x95\x44\x9c\xa8\xf4\x46\xb2\xdb\x7e\x4c\x20\x56\xfc\xf9\x3c\xd5\x5d\xe2\x36\xf2\xad\x7e\x4f\xf0\x20\x28\x59\x35\x68\x63\x71\xa8\x2d\xf5\x3e\x25\x73\x5f\xa2\x8d\x13\x48\xe4\xcd\x42\x9b\xc1\x21\x2c\xd2\x8f\x8e\xf4\xb8\xb0\x1e\x54\xa6\x51\x96\x77\xad\x3b\x14\x6c\x8c\xa2\xcd\x0e\x37\x90\xbf\x63\xdf\x7c\x15\xf6\x6e\xa9\x51\x19\x3e\x1f\x8e\x85\xdb\x3a\xdb\xd7\x8b\xd1\xd5\x6f\xeb\x4a\xd7\xcf\xa0\x5b\x31\x1b\xfe\x53\x2b\xd1\x4c\xdb\x46\x4a\xf4\x4b\xe3\xf6\x81\x94\x25\x4c\xb1\xb6\x1d\xd3\x0e\x23\x11\x6a\x86\x88\xeb\xef\x66\x38\x5d", 132, { 0x75, 0x3e, 0x93, 0xdd, 0x62, 0x64, 0xdc, 0x2b, 0xe9, 0x63, 0x91, 0x07, 0x52, 0xd6, 0x66, 0x5b }, { 0x67, 0x53, 0x0c, 0x41, 0x3b, 0xb7, 0x4d, 0x49, 0x68, 0xd2, 0x30, 0xdb, 0x61, 0x39, 0xcb, 0x24 } },
{ "\xeb\x5e\xc2\x4a\x33\x06\x75\xda\xa8\x5f\xd7\x95\x29\xfe\x81\xc2\x8a\x96\x2b\xa8\x14\x21\x42\x32\x2b\x39\xb5\x9f\x22\xdd\xed\xf9\x5a\x30\x1d\x19\x82\x5d\xd7\x40\x54\xe2\x04\x7b\x49\x84\xb0\x57\xa5\xb3\x22\x36\x3c\x75\xe5\x09\x08\xd2\x0d\x9b\x88\xdb\x52\x5d\x0e\x5a\xaf\x56\x78\x16\x12\x32\x96\x7f\x8d\x3d\x02\xea\x76\x4c\x95\x85\xd4\xe6\x2b\xa2\x45\x14\x2b\x82\xb9\xc5\x77\xea\x06\xe0\x9b\x9a\x5c\xc2\xe1\x74\xd1\x96\xe8\xfe\x57\xb3\x2e\xe0\x95\xea\x04\x78\x7c\xba\x0c\xdb\x74\xa4\x2e\x33\xd3\x9a\x53\x46\x36\x3c\xc4\x54\x49\x9d\x92", 133, { 0x5b, 0x51, 0x31, 0xa6, 0x20, 0xde, 0xfa, 0x85, 0x46, 0xc6, 0x52, 0x5b, 0xdc, 0x77, 0xae, 0x85 }, { 0x24, 0x8f, 0x35, 0x73, 0xe5, 0xb5, 0x9b, 0x2e, 0x00, 0x1a, 0x33, 0x01, 0x7b, 0x65, 0xe5, 0x82 } },
{ "\x58\xc5\x17\xa8\x74\xfd\x1e\xa8\x2e\x23\xc1\xc3\x1e\x4d\xd4\xd1\x81\x30\xdf\x35\xab\xa8\xdd\x18\x3f\x7e\xec\x2e\x28\x86\x08\x3f\x32\x84\x54\x57\xd7\x9a\xdd\xd5\x38\xbd\xdf\x69\x9b\x5c\xc5\x96\x42\x9c\x51\xd5\x6f\x7f\xb3\xb7\xac\xa4\x29\x02\x41\xda\x6c\xc9\x5a\xd0\x3f\xcb\xb8\xe7\xe3\x45\x92\xad\x5f\xe7\xc6\xef\x83\x1d\xc9\x44\x01\x72\x3d\xb7\x33\x67\x08\x34\x6d\x72\xe8\x14\x41\x0d\x1d\xde\x78\x73\xb4\x44\xde\xc6\xb5\xe0\xa9\xfa\x08\xab\xc6\x9d\xa6\xff\xee\xd9\xbe\xe2\xf0\x32\xe2\xbe\x92\x91\xbe\x36\xeb\x1e\x25\xce\x3e\xcc\xe7\x77", 134, { 0xd5, 0x55, 0xa5, 0xc2, 0xf2, 0xf5, 0x88, 0xaf, 0xf0, 0x7b, 0x26, 0x5b, 0xba, 0x99, 0x1d, 0xca }, { 0x4d, 0xa6, 0x98, 0x88, 0x4c, 0x22, 0x7d, 0x44, 0xcd, 0xfa, 0xc5, 0xf1, 0xb8, 0x39, 0xc7, 0xd9 } },
{ "\x59\xa1\x04\xeb\x2e\x94\xed\x06\x22\x7c\xd2\x7d\x2a\xc5\xad\x03\xf7\xd9\xa1\x45\x5f\x58\x84\x46\xfe\x92\x01\x6c\xda\xf9\x03\x7f\x34\x34\x39\xd5\x8a\xa7\xc9\x4c\x88\x03\xb5\xf2\x7c\x21\x53\x26\xc2\xd6\xa2\xbb\xdb\xc3\xde\xf6\x23\x27\x08\x14\x4f\x92\xbf\x22\x86\x57\x81\x92\xe6\xde\xec\x0a\xd6\xa7\xb3\x41\x38\x53\xee\xd4\x46\x39\x5d\xb5\x7d\x57\xa3\xca\xbd\x14\x3d\xb1\x44\xea\x1b\x81\x14\x1d\x0a\x9c\x96\x58\xdb\xe7\x57\x4b\x8d\xac\xea\x00\x79\x8b\x64\x4e\x0f\x34\x6d\x81\x9c\x20\x9d\x4d\x25\xd2\xa9\x7b\x47\xbe\x22\x6b\x25\x78\x8a\x11\x6e", 135, { 0x53, 0x69, 0x47, 0x81, 0xc6, 0x9b, 0x0b, 0x4f, 0xe6, 0x6f, 0x8c, 0x08, 0x4d, 0x9b, 0x3b, 0x0e }, { 0x83, 0xeb, 0x78, 0x45, 0x73, 0xb3, 0xe8, 0xb6, 0xfb, 0xf6, 0xa8, 0x67, 0xa1, 0xf2, 0xa6, 0x22 } },
{ "\x1c\x92\x9a\x2b\x73\xe8\x66\x71\x9a\x17\xc9\x35\x8d\x7a\xa4\xc6\x7d\xcb\x06\xf3\x80\x67\x64\xa6\x26\xae\x1d\xb3\xc6\x10\xfa\x04\x0d\x25\x92\x77\x5a\x19\x50\xfb\x15\x00\xe1\xaf\x0d\x9d\xdf\xa2\x69\x1e\x15\x64\xe1\x53\xc4\x83\x8f\x4f\x68\xaf\x7c\xd0\xfa\xa0\xc6\x7e\x6b\xc0\x37\x9c\xb2\xad\x3c\x59\x87\xd3\x98\x38\x77\xb9\xe6\x78\x39\xc3\x2c\x31\xb7\x63\x1d\xaf\xe5\x51\xd8\x9e\x00\x97\xfa\x57\x0c\x98\x2a\x02\x61\x95\xab\x0a\x46\xf2\xf9\xbd\x0b\x5c\x3a\x2b\x89\x8f\x18\x7d\x93\x9d\x57\xea\xbc\x19\x1c\xb6\xea\x8d\x12\xae\x4e\xa1\x5a\x46\x31\xeb", 136, { 0xf2, 0xaa, 0xfa, 0x05, 0xad, 0xba, 0xc1, 0xb1, 0xe6, 0x29, 0x67, 0x43, 0xfe, 0x22, 0x33, 0x1f }, { 0xca, 0x71, 0x5f, 0x20, 0x78, 0xd9, 0xcd, 0xd7, 0xb4, 0x72, 0xff, 0x42, 0x45, 0xdb, 0x7d, 0x41 } },
{ "\xb9\xf5\x60\x3a\x8d\x60\xb8\x5a\x4a\xe7\x3e\xbd\x35\x79\x4a\x24\x5a\x7f\x6c\xfe\xef\x18\x82\xe4\x09\x09\x07\xb0\xb8\xc6\x7b\x5e\xf2\x65\x6b\xfd\xb3\x28\xe9\xa5\xa0\x73\x9a\xab\x1b\x38\x1b\xb4\xb4\x25\xdb\x72\x2d\xb1\xba\xf5\xa4\x62\xff\x00\x3d\x67\x4d\x8d\xbb\xce\xa2\x6c\x7c\xd8\x89\x7c\xdc\x3e\x2e\x30\x60\x04\xb1\x9b\x50\xf0\x33\xb0\x6c\x34\x1d\x1c\xf8\xe9\x94\x55\xa7\xe4\x88\x2e\xf1\x68\x4a\xfc\x57\x26\x16\xac\xd1\xf9\xa8\xb9\xf8\x7e\x68\x8b\x45\xe6\xd3\x19\xac\xaa\xfd\xd3\x5a\xdf\xe4\x80\x1a\xe3\x0a\x91\xd6\x9a\xa2\x1a\x29\xf6\x66\x78\x3f", 137, { 0x29, 0x1b, 0x93, 0x9e, 0x90, 0xce, 0xd4, 0x7d, 0x1d, 0x7e, 0x44, 0x25, 0x94, 0x60, 0xa5, 0x49 }, { 0x3f, 0x8d, 0xe6, 0x89, 0x0b, 0xc8, 0x95, 0x33, 0x50, 0x58, 0x19, 0x57, 0x05, 0xf3, 0x59, 0x8d } },
{ "\x0d\x2d\x9e\x30\x43\x71\x65\x86\xe2\x4f\x01\x44\xc9\x1e\xf7\xde\x63\x1d\xdb\xd4\xd6\x53\x14\x80\xa8\x69\xe4\xd6\x73\x87\x7d\xd8\xb7\x31\x64\x8e\xeb\x6a\x1b\xc6\xdd\x66\x05\xe8\x05\x14\x12\x09\xc0\x78\xf6\xfc\x63\x5e\xd3\xeb\x47\x87\x4c\x99\xec\xa5\x5a\xc3\xa1\xa3\xc8\x8d\x2b\x6d\x1a\xab\xe1\x24\xf5\x70\x0a\x05\x92\xf8\xe3\xe7\x95\xc6\x11\x7f\x34\xc3\xdb\x73\xce\x5f\xfa\x21\x95\xbe\x77\x68\xdf\xc9\xdc\x2c\x37\x67\x2a\x5c\xa1\xaf\xe6\xee\x9e\xc3\xd8\x96\xb7\x08\x57\x69\xe1\x87\x6e\x60\x5b\x68\x4a\xdb\x81\x88\xa0\xef\x2f\xc3\x27\x07\x39\x21\x56\xc7", 138, { 0x19, 0x16, 0x80, 0x9f, 0x02, 0x45, 0x4b, 0x9e, 0x72, 0x84, 0x96, 0x3c, 0xb3, 0x60, 0x2e, 0x88 }, { 0xc3, 0x59, 0xf1, 0xed, 0x13, 0x84, 0xd2, 0xb0, 0xe8, 0x85, 0x31, 0x08, 0x1f, 0x88, 0xa2, 0x24 } },
{ "\x36\xbf\x0a\xc9\x12\x5f\x89\x12\x17\x86\xab\x50\xa9\x5e\x16\x1f\xc5\xe8\xee\x1c\x9c\x9b\x47\x60\x11\x45\x62\xb3\xac\x92\x99\xc3\x10\xd2\x18\x13\x85\x00\xb1\xe6\x39\x48\x8e\xda\x7e\xf8\x6a\xdf\x2e\xb5\x80\xe4\xb1\xd3\xf6\x5f\x4b\x59\xc8\x23\x17\x11\xfa\xd5\x9d\x68\x55\x01\xc4\xe1\xda\x24\xe4\x6e\x69\x98\xc5\xe5\x63\xb9\x83\x7c\xc1\x49\x90\x1a\x51\xe5\xdc\x5d\x3d\xb6\xad\x43\x1d\xcd\x06\xdd\x11\x5f\x78\x41\x0c\x05\x2a\x7b\x63\x7e\xb9\xdc\x56\x56\xd8\x0f\xbd\x05\x16\x45\xe6\x45\x0b\x76\x6c\xbe\x83\xf6\x00\x8d\x54\x4e\xb1\x5b\x3e\x30\xe1\xc9\x57\x02\x78", 139, { 0xcc, 0x87, 0x3e, 0xa0, 0xf6, 0xcb, 0x3c, 0xba, 0x0d, 0xc6, 0x8e, 0x2c, 0x33, 0x18, 0xab, 0x54 }, { 0xb0, 0x01, 0x86, 0x0a, 0x25, 0x1a, 0x9c, 0x7c, 0x64, 0xa7, 0xa4, 0x20, 0x3f, 0x5c, 0xd1, 0x77 } },
{ "\x50\x62\x10\x48\x03\x0d\x6d\x07\x74\x7a\xd7\x89\x5b\x36\xe2\xe4\x22\x76\x12\xde\x27\x7f\x77\xf6\x38\x8b\xcb\xb4\x1d\xe8\xa9\xe9\xf1\x65\x62\x5d\xe7\xaa\x74\xd2\x47\xb7\xfd\xa9\xaa\x20\x79\x90\x96\x2b\xf7\xef\xf6\x2b\x6d\x5f\x89\xe9\xd7\x2d\x7e\xbe\x1f\xc4\xde\x8c\x22\x93\x58\xce\x18\x1b\x04\xc0\x5a\x56\x51\x84\x7f\x55\xa0\x3d\x68\x20\xb2\x4a\x4b\x5c\xe5\x94\x4f\x1e\x0a\xd5\xc8\x5a\xc8\x4e\x46\xea\x4a\x70\xd9\x25\xd3\x66\x44\x1c\x9b\xa0\x83\x4a\x23\xd2\xb7\xd7\xb6\x14\xcf\x7d\xb3\x33\xf7\x68\x95\x13\x72\xe5\xd5\x9e\xde\xf8\x8a\xd7\x55\xb9\x5c\x4d\xad\xa2", 140, { 0x22, 0xbf, 0xcf, 0x0b, 0x29, 0xc5, 0xd1, 0x78, 0x57, 0x41, 0xb4, 0xa6, 0x0a, 0x8c, 0x84, 0x0f }, { 0x29, 0xe7, 0xdb, 0x14, 0xac, 0xbc, 0xf6, 0x2d, 0xf9, 0x0c, 0x61, 0xf7, 0xe3, 0x12, 0xf1, 0xe8 } },
{ "\x67\xfd\x3b\x15\xaf\x02\x6c\xcb\xe8\x5d\xdb\x55\x63\x3a\xb2\xd2\xe7\x76\x65\xee\xd3\x80\xa6\x48\x47\xc9\x36\x40\xd6\xa8\x50\x9b\x52\x70\xec\x40\xdd\x0b\x69\x0b\xfb\x6b\xbe\x13\x1e\x48\xbe\x01\xc8\x3a\xaf\xbb\x65\xd1\x14\x17\xe1\xbf\xb6\x08\xe8\x47\xd4\x98\x13\x90\x0c\xb5\x2b\xd0\x00\x59\x6a\xe1\x71\x6a\x0c\xd6\x70\x2a\x64\xb1\x86\x94\x36\xd7\xa8\xe3\x75\x44\x3b\xcc\x6e\x84\x4c\xe3\x96\xe5\xb1\x0a\x06\xb9\xe5\x89\x8f\x50\x60\xbc\x36\xcc\xcf\x17\xba\x9e\x52\x97\x38\xb6\x71\xdf\xad\x96\xdd\x87\x13\x42\x14\x69\xd1\x68\x93\x60\x41\x9d\xc4\x44\x99\xef\x3f\xf5\xec", 141, { 0x04, 0xcc, 0xed, 0x85, 0x07, 0x84, 0x3e, 0x21, 0xe3, 0xf1, 0xbb, 0xd0, 0x50, 0xd3, 0x2d, 0x87 }, { 0x3b, 0x1b, 0x54, 0x40, 0xa5, 0x51, 0x16, 0xa6, 0x8b, 0x2f, 0xd4, 0xd6, 0x9e, 0xd2, 0xb9, 0x83 } },
{ "\xc1\x2c\x56\x13\x26\xbf\x59\x62\xf2\xf3\x7a\x26\xd0\x56\x00\x26\xb3\xb4\xe8\xae\x48\xde\x95\xe4\xfa\xe3\xd9\xa4\xf8\x77\x8c\xce\x39\xb0\x19\x07\x5e\x8e\x7a\x13\x27\xd8\x5f\x38\x9b\x90\x12\x69\xa8\xd7\x37\x91\xec\xc7\x48\xe0\xbd\x42\xcf\x22\x53\x61\x6f\xe8\x13\x97\xe7\x54\x1f\x8a\x0c\x7e\x37\x93\x61\x64\xc5\x69\x32\xd3\x26\xd6\x8c\xdb\x7d\xed\xf0\x1f\xa7\x1f\xb8\xcc\xcd\x1e\x4c\x50\x91\x43\x4b\xe4\x33\x61\x62\x20\x8d\x64\xf9\x86\x92\x74\x00\x40\x42\x9c\x40\xf6\xd4\x3e\x1f\x60\x6e\xd9\xb9\x35\xe9\x1f\xa6\x82\x81\xad\xda\xe2\x15\xf6\xfb\x9f\x71\xe8\x12\x4f\x77\x99", 142, { 0xe9, 0xe5, 0x46, 0xd4, 0xbd, 0x09, 0xc8, 0x38, 0x40, 0x2c, 0x43, 0xcb, 0x97, 0xc5, 0xbe, 0x98 }, { 0x87, 0xa8, 0x2f, 0xdf, 0x52, 0xc5, 0x73, 0x00, 0x09, 0x25, 0x7c, 0x2e, 0x84, 0x31, 0xec, 0x29 } },
{ "\xaa\xb8\x13\x9c\x1e\x6e\x14\xc0\xb0\xf2\x74\xfb\xed\xaf\x08\x1e\x49\xc5\xad\x56\x25\x9e\xb7\x3a\x98\x5d\xff\x85\x13\xad\xbf\xbd\x61\x68\x5d\x27\x4c\x4f\x75\x91\xc2\x12\xc0\xed\x3b\x76\x6f\x84\xc4\xcc\x3a\xae\x45\xec\xfc\x5d\x12\x2f\xc2\x39\x9d\xf4\x2e\x25\x30\x46\x19\xb8\x87\x41\x54\xa4\xe3\x1d\x10\x30\xbb\x57\xd4\xb1\x0a\x54\x2c\x74\x49\x44\x2f\x56\x5e\x2d\x3a\x82\x14\xc9\x44\x62\x20\x77\xae\x33\xdf\x98\xd9\xca\x92\x15\x6c\xef\xdf\xf1\x63\xdf\xec\x7e\xf2\xaf\x08\xa2\xab\x1b\xa5\x82\x35\x0b\x38\xb1\x77\x7c\x34\x81\xd4\x83\x0d\x93\xa3\xfd\x8f\x08\x70\x8a\x25\x14\xcf", 143, { 0xa5, 0xaf, 0x4b, 0xe8, 0x4a, 0xc5, 0x78, 0x01, 0x7a, 0xa2, 0x2a, 0x1c, 0x40, 0x9a, 0xc4, 0x10 }, { 0x28, 0x10, 0x2d, 0xe4, 0x36, 0xd9, 0x10, 0x69, 0xfa, 0x47, 0x7f, 0x69, 0xe2, 0x29, 0x49, 0x24 } },
{ "\xe0\x7b\x80\x18\x93\x15\x33\x75\xb2\xef\x1c\x9c\x9b\x28\x8f\xf4\x6c\xad\x2d\xe2\xa0\xf0\xcf\x99\xd5\xf8\xb4\xf5\x5b\x10\x09\xf3\x1f\xc6\xcd\x23\x44\x5e\x30\xea\x50\x2c\x38\x28\x24\x36\x37\x18\xf9\x9d\x79\xb0\xd7\x0a\x4d\x0c\x22\xce\x09\xe2\x7f\x35\x5b\x0c\x65\x6f\xdc\x62\x1c\x4a\x9e\x54\x9c\x33\xca\x35\x63\xe2\x87\x03\xbb\x4a\xcc\xf9\x97\x03\x96\xc1\xc4\x84\xdc\xe1\xc6\x4e\xcc\x47\xa4\x0f\xce\x38\x4c\xcc\x84\xd1\x1a\x41\xd1\xea\x2a\xb8\xe1\x7e\x0e\xca\xc6\xe8\xd7\x9b\x34\x59\xaf\xc8\x69\x58\x4e\x73\x83\x33\xdf\x67\xeb\xca\xe8\x82\xa8\x93\x4e\x1e\xb7\x88\x9c\xc6\x97\x27", 144, { 0x23, 0xa7, 0x9e, 0x3c, 0xbf, 0x5f, 0x8e, 0x8d, 0xad, 0x04, 0x11, 0x24, 0x57, 0x59, 0x9e, 0x47 }, { 0xc9, 0x88, 0x89, 0xdb, 0x1d, 0x95, 0x16, 0x4e, 0x3b, 0x82, 0x5a, 0x22, 0x0c, 0xe3, 0xb2, 0xb0 } },
{ "\xbb\x38\x5e\x71\x0a\x55\xc6\xcb\xf5\x33\xe6\x5c\x2c\xd2\x23\x65\x71\xa5\xd8\xfe\x97\x5f\x0e\x38\xfd\x7e\x17\xd9\xf7\x88\xf8\x61\xf9\xa1\x1c\xca\x4b\xf3\x43\xdb\x28\x94\xa5\x4d\x7c\xea\xd4\x90\xb4\x0b\x73\x59\x7a\xcc\x93\x46\xb0\xaf\xd4\x00\x4f\x6a\x7e\x0b\xea\xec\x8b\xe8\xdf\xa1\xf8\x1c\x1d\x33\x79\xa3\xe1\x63\x7a\x13\x77\x23\xf0\x28\x31\x07\x34\x4c\xee\x39\xa5\x43\xe4\xd7\xd4\x3d\x11\xce\x79\x19\xf9\x29\x6a\x89\x6f\x3a\x90\x00\xc4\x99\x69\x06\xb8\x73\xd8\x49\x69\xb9\xea\x04\x80\xc0\xdd\x62\x35\x1c\xb0\x24\xab\x6a\x2a\xf7\x3c\x25\x94\xd1\xca\xe5\xf5\x84\xb5\xfe\x63\x89\xe2", 145, { 0x81, 0xf2, 0x6c, 0x8b, 0x9c, 0x7a, 0x24, 0x98, 0x39, 0x7e, 0x7c, 0x67, 0x25, 0x1b, 0x22, 0x8a }, { 0x96, 0x52, 0x25, 0xa3, 0x84, 0xbb, 0xd5, 0xac, 0x23, 0xa1, 0x70, 0x37, 0xf0, 0xa0, 0x5e, 0x9c } },
{ "\x34\xd6\x24\xa0\xcf\x14\x01\xa9\xd1\xf4\x20\xd2\xc4\x66\x00\xf1\xfe\xdc\x0b\x54\x28\x3b\x68\xa6\xf5\x79\x9c\x52\xda\x7e\xe5\x02\x05\x59\x17\x75\x65\xbd\x8f\x64\x04\x00\x4b\xf5\xe3\x9b\x04\x61\x6b\xee\x87\x25\x56\x2b\x66\xd1\xbb\x63\x50\x9c\x1e\x37\xb9\x6b\xca\x86\x06\x99\x0f\x48\xa5\xb7\x6e\xfc\x9f\xc7\x39\xbe\x62\x5b\xd7\xe3\x2b\xde\x4d\x5d\xa5\x8e\xc0\x27\xa8\x0e\xdb\xd0\x34\x50\x29\x39\x75\x11\x5d\xc3\x84\x27\x82\x5c\x3d\x95\xef\xe3\x41\x46\x76\x68\xad\x8d\x91\xe1\x0b\x29\x12\x44\xbf\xdc\xb4\xa9\x32\xb9\xcc\x75\xc3\x76\x3e\x25\x5a\xbe\x70\x63\xc8\x37\x0b\x8f\x23\xdb\x93\x89", 146, { 0xcc, 0x12, 0x53, 0x4d, 0xf0, 0x34, 0x15, 0x08, 0xa2, 0xcf, 0xce, 0x3b, 0x39, 0xdc, 0xcb, 0x95 }, { 0xb8, 0x58, 0x76, 0x49, 0xf8, 0xe5, 0xf7, 0xf1, 0xc2, 0xc3, 0x10, 0xb5, 0x73, 0x45, 0x34, 0x7f } },
{ "\xca\xbd\x19\x7e\x77\x58\x5f\x7c\x04\xce\xd9\x7c\xca\xcb\x60\x60\x63\x6c\xcc\x2b\x18\xc4\x2f\xf7\xf0\x22\x57\xa9\x89\x28\x2a\xdf\x02\x2a\xc5\x79\x5d\x75\x8a\xdc\xa9\x02\x2d\x00\xdd\xe5\xac\x07\xcf\xcb\x6e\xd2\x45\x69\xc7\x21\xbe\x0c\x2c\x13\xa4\xb0\x06\x95\x0b\x7b\xa6\x7d\xc3\x77\x5a\x47\xf2\x46\x9d\xdf\xf1\xd0\xf3\xe2\x75\x74\x60\x95\x8b\x3a\xb2\x3b\xe4\xe3\x60\x03\x71\x04\xe7\x99\xe1\x35\xa9\x48\xf7\xb1\xe7\x99\xcc\x28\x92\xca\xfe\x33\xae\xff\xe6\x96\x39\x81\x2f\xc6\x36\x69\x17\x64\xac\x26\xdd\x7f\x19\x85\x91\xd0\xf5\x9b\x83\x6d\xdc\xd9\x90\x97\x4a\x5e\x21\x91\xe9\x25\xfc\x52\x75", 147, { 0xb2, 0x7a, 0x58, 0xbf, 0x11, 0x80, 0x97, 0x95, 0xb8, 0xda, 0xf9, 0x51, 0x63, 0x5c, 0x9f, 0xa6 }, { 0x43, 0x50, 0xf3, 0xe0, 0xe6, 0x3b, 0xa6, 0xc4, 0x80, 0x29, 0xa7, 0x81, 0xe8, 0xd5, 0x7f, 0x12 } },
{ "\xf6\x8c\xd1\xae\x1b\xba\xf6\x71\x7e\x42\xe5\x4b\x67\xba\xa5\x13\x4e\x58\x0f\x53\x19\xd7\xc2\xff\x7a\xef\x04\xfb\xd2\x23\x18\x4f\x70\xe3\xec\xb1\xa7\xa8\x98\x36\x83\x8c\xd6\xaa\x2e\x8c\xc0\x63\x21\x0a\xf5\x98\xc1\x9d\x23\x7a\xee\x7c\xe8\x53\xd9\x87\x96\x2a\xdf\x85\xcd\x03\x34\xfd\xd4\x65\x79\x2a\x43\xb7\x06\x26\xc8\x75\x21\x35\x87\xa8\x65\x4e\x69\xfa\x5c\xdb\xfa\xe3\x15\x35\x72\xa6\xe8\x95\x9f\x2f\x8c\xe7\x6a\x79\xe8\x05\x8f\x2f\xca\x08\x90\xb1\x18\xd1\x74\x90\xb7\x14\x22\x19\xa5\x6f\x7b\x78\xa9\xc6\xfd\x8a\x42\x83\x76\x59\x47\xca\xee\xf7\x9e\x81\xea\xda\x8a\x4f\x87\xe8\x76\x32\x82\x9a", 148, { 0x5d, 0x6d, 0xb7, 0xee, 0xee, 0x0b, 0x35, 0xd9, 0x73, 0xb8, 0x5b, 0x00, 0x54, 0x21, 0x4e, 0xb2 }, { 0x7a, 0x4d, 0xa5, 0x2c, 0x6c, 0x7d, 0x28, 0x64, 0xcb, 0x6c, 0x52, 0x27, 0x13, 0x3e, 0xcd, 0xe2 } },
{ "\x00\xd3\xb6\xd2\xbc\xf3\xb9\xd0\x1a\xc0\x79\x9e\x51\xad\xe6\xfd\x68\x1c\x0a\x01\x8e\x11\x40\x12\x22\xad\x5b\x5b\x63\x30\xf6\x95\xeb\x67\xbd\xa2\x62\x48\xd9\xfc\x6a\x86\x18\x7b\xbd\x05\x2d\xa3\x2a\x4b\xb3\xb1\xb1\x22\x12\x92\x8c\xd2\xec\x57\xb6\x50\x1a\x22\xb2\x2c\x20\xa8\x5f\x80\xfa\xa1\xa8\x43\x8b\x51\x75\xd1\xe8\xbd\xb3\x2a\x2e\x8a\x24\x4a\x81\x1b\x0f\x64\x0a\x11\xc1\x7d\xd4\x69\x84\xf1\x8b\x43\xb0\x1d\xd7\xdd\x16\x16\x97\x1a\xf4\x30\x94\xa5\x4a\x41\xd4\x9d\x50\xf4\x2c\xe1\xb3\x2a\xae\x7b\x3c\xc6\x78\x24\xa8\xe0\x92\x8b\xca\x48\xbe\x90\x27\x99\x38\xc8\x60\x13\xb8\x20\xb8\x6b\xfa\xde\x93", 149, { 0x7e, 0x7b, 0xe2, 0x3d, 0xef, 0xa1, 0xd7, 0x8a, 0x3b, 0x1b, 0x8c, 0x3c, 0xf7, 0x7d, 0x01, 0xfe }, { 0x38, 0x30, 0xb4, 0x0e, 0x14, 0xac, 0xc8, 0xec, 0x8f, 0xb5, 0xd0, 0x1d, 0x97, 0x70, 0xae, 0x36 } },
{ "\x11\x06\x7c\x6d\x5d\x61\x17\xb2\x49\x67\x67\x30\xc3\xa2\x67\x06\xdb\x44\x0a\xa9\x4c\x29\xac\xa3\x18\x14\xb7\x2e\x5b\x3f\x7e\x86\x3f\x22\x50\x24\xfe\x30\xd0\x74\x9a\x24\xb8\x3a\xc1\x43\x8b\xb8\x65\xf9\xe6\xe4\x6b\x2c\x90\xc6\x5b\x9e\x45\xc8\xe9\x84\x78\x02\xce\x6f\xaa\xb9\xb2\x99\xe9\x4e\x9b\xc0\x35\x97\xb1\x19\xf7\xd6\x87\xec\x23\x29\xfe\x5b\x42\xe1\x58\xa1\x73\x6f\xe0\xd8\xb0\x4d\xcd\x63\x28\x2b\xe7\xa7\x28\xc7\x71\x18\xed\x17\x49\xfa\xcd\x0e\x4b\x00\x54\x74\x2a\x27\x3d\x47\xca\xc7\x5b\xee\x5b\xfd\x9e\x2a\xee\x16\x71\x29\x26\xf4\xc8\x66\x81\x43\x52\x3c\x98\x73\x54\x65\xdc\xfe\xf8\xc2\x1a\x9e", 150, { 0x82, 0xcc, 0xd4, 0xbe, 0x1d, 0xba, 0x4d, 0x3e, 0x9e, 0x54, 0x86, 0x70, 0x46, 0xd2, 0x18, 0x46 }, { 0xd4, 0xb2, 0x40, 0x20, 0x6c, 0x7a, 0xf3, 0x27, 0x01, 0xc8, 0x9f, 0xa2, 0x99, 0x4f, 0x47, 0xa8 } },
{ "\xe5\x32\x3b\xe1\x6a\x25\x94\x43\x77\x84\x89\x4b\xa4\x1f\xdb\x94\xa7\xa9\x54\xfd\x45\x67\xda\xc9\x45\x25\xb4\xef\x7d\x3e\xc5\x0f\xf2\xc5\xfd\x3f\x09\x6b\xb1\x5c\x4a\xce\x66\x13\x8e\x61\x71\xea\x20\xf8\x38\x1c\xad\x15\x92\xf4\xd6\xaf\x80\x0c\x05\xcf\x30\x99\xf9\x17\x44\xe4\xfc\x54\x69\xf3\x38\x78\x5f\x35\xd7\xa6\xc2\xfc\xa2\xa3\x03\x43\xb2\x2a\xfb\xdc\x83\xdc\x28\x03\x85\x7c\xba\x1f\x60\x31\x2a\xe0\x14\xb9\x1e\x63\xd6\x39\x09\x90\xbe\xde\x5b\xa2\x48\x81\xd2\xf9\xeb\x90\x67\x85\x5a\xf4\xff\x7e\x06\x55\xad\xa9\xc0\xa2\x7c\xf8\xf3\xa5\x44\xe8\xac\x25\x59\xcc\x8e\x29\x7c\x4c\x0f\x87\x67\x17\xdc\xdd\x10", 151, { 0xf9, 0xd8, 0x1b, 0x42, 0xb3, 0xc8, 0xa6, 0x62, 0xac, 0xfe, 0xd2, 0x23, 0x7c, 0x36, 0x14, 0xb7 }, { 0xca, 0xff, 0xe6, 0xa1, 0xf3, 0x16, 0xc5, 0x95, 0x17, 0xf2, 0x39, 0x82, 0xd1, 0xb5, 0x81, 0x83 } },
{ "\x57\x65\x64\x85\x97\x18\x6a\xc2\x87\x19\x77\xed\x01\x08\xda\xea\x75\xb9\xcd\xe4\x00\xe3\x0b\x90\x40\x66\x1b\x8d\xb1\x66\xe7\xfb\xe4\x37\xe6\x42\x9e\x8c\x64\x07\x41\xca\x3c\x07\x20\xd8\xab\xfa\xe1\x84\x56\x6d\xbb\xda\x39\xea\x88\xdf\x40\x48\x8c\xf7\x0a\xb5\x7e\xc0\x6b\xa0\xde\x5c\xc0\x37\x9f\x96\x76\x13\x67\xb7\x6c\x3a\xb7\x12\x18\x39\xbc\x9d\x15\x0d\x89\x73\x2e\xe6\x6b\x14\x3d\x19\x3b\x98\x43\xed\x30\xbc\x83\x0d\xc8\x9e\x36\x40\x0b\x62\x82\x7c\x43\x50\xce\x63\xc5\xe1\xe0\xfc\x56\x51\x8b\xd5\xb6\x3d\xf0\xb1\x2c\x7b\x0e\x99\xde\xb2\xf3\x90\x5a\xf7\x63\x45\xe5\x6b\xb7\x10\x75\xf1\x84\x9c\xca\x68\x41\x0d", 152, { 0xdd, 0x84, 0x8f, 0x20, 0xee, 0x17, 0xbe, 0xd6, 0xd8, 0x3d, 0xbf, 0xe5, 0x45, 0xca, 0xd8, 0xc5 }, { 0x27, 0xf8, 0x81, 0x3e, 0x50, 0x9b, 0x53, 0x87, 0xf4, 0xf1, 0x4d, 0x55, 0x46, 0x51, 0x8f, 0xf8 } },
{ "\x26\x82\x00\x9d\xc1\x7a\x91\x13\x36\x6f\xb0\x7f\x33\xe5\xbb\xe7\x47\xd3\x74\xc1\x47\x83\x49\x24\xca\x1e\x2c\x97\x25\xa4\x82\xed\xbc\xdf\xe5\xae\xb6\xca\xb6\xfe\xde\x7d\x22\xf5\xd7\x27\x77\xf8\x74\x3f\x34\x22\x5b\x34\x12\x89\x17\xf0\xc1\xd5\xde\xe6\x49\x05\x7c\xe6\x97\xad\x0f\x23\x62\x85\xf0\x4b\x33\xfa\x40\x65\xfc\xfa\xa4\x5a\x56\x86\x58\x00\x0c\x52\xfb\x5b\x14\x0a\x78\x99\x9f\xed\x64\x95\x35\xef\xa9\xfd\x2b\x4a\xb0\xbe\x50\xe8\x99\xed\x76\xcc\x34\x9c\x79\x3d\x0d\xf9\xcb\xca\xf5\x21\xfb\xd0\x19\x44\x25\xae\xd9\xc9\x9b\xcf\x3d\x03\x80\x6e\xda\xd0\x55\x96\x8c\x8f\x68\x7b\x0e\x57\x35\xbd\x5c\x11\x21\xb6\x14", 153, { 0xe7, 0x56, 0x48, 0x9d, 0x9d, 0x9d, 0xdc, 0x89, 0xc6, 0x53, 0x78, 0x54, 0xa4, 0xd1, 0x80, 0xa3 }, { 0xb3, 0xc8, 0x73, 0x1e, 0x5b, 0x41, 0xbe, 0x82, 0x37, 0x44, 0x45, 0x21, 0xc9, 0x2f, 0xd0, 0x68 } },
{ "\x52\x8e\x45\xe6\xab\x1c\x68\xf2\x82\x60\xe3\x56\x23\xa1\x80\x3f\x2f\x71\x3c\x96\x7f\x17\xb9\xad\x5a\x0c\xee\x2f\xa8\x11\x8f\x33\x82\xb9\x12\x4c\xdd\xca\x07\x6b\x5d\x77\xfa\xdc\xdb\x59\x3b\x8d\x57\x6b\x36\x7f\x5d\x33\x7e\x94\x65\x33\xdf\x48\xe9\xdc\x4c\xfb\xd9\xed\x23\xfc\xcd\xea\x21\x5f\xf6\x5d\x45\xa3\x65\x80\xd6\x50\x32\x11\xf3\x56\x49\x60\x77\x99\x91\x56\xfa\xf9\x15\x5d\x22\xc3\xcd\xd9\x23\x51\x17\x43\x99\x6d\xad\xde\x76\x1c\x8c\xa8\x67\x65\xa0\x3e\x88\x55\x93\x79\x60\x1f\xa4\x92\x59\x45\x71\xcd\xdf\x34\xc4\x05\xff\x7b\x22\x89\xd4\x45\x99\xe2\x54\x97\x22\xa6\x4e\x1b\x2b\x11\x44\x03\xff\xb2\x42\x89\xf2\xdb", 154, { 0x68, 0xb4, 0xb7, 0x35, 0x04, 0x93, 0x28, 0x0e, 0x8c, 0xa6, 0x5e, 0x33, 0x40, 0xcf, 0x89, 0xbe }, { 0xb9, 0xe5, 0xee, 0xf2, 0x37, 0x8c, 0xc4, 0xd7, 0x1f, 0xca, 0x46, 0x76, 0xaa, 0xbb, 0xbe, 0x8e } },
{ "\xa4\xb0\xa8\xb9\x2f\x70\xb3\x88\x6c\x77\xc2\xf4\xe3\xad\xbe\x5b\x73\x6c\x96\x3a\x13\x28\xf5\x06\x11\x51\xcd\x3a\x7e\x95\xa7\xe0\xcd\x25\xcc\xa2\x91\xfd\xd3\xfa\x73\xde\xe7\xed\x2b\x0a\xbe\x77\xf6\x31\x9d\x31\xb4\xe2\x7f\xa5\xb7\x95\x77\x03\x77\x68\xd3\x9f\xe0\x9d\x52\xf5\x3c\x70\xbc\xd8\x94\xad\xc6\x2e\xd8\x7c\x74\xbb\x01\x25\x7f\xcb\x57\x54\x4b\xc6\x1e\x7a\x6d\x04\x00\x92\x55\xf8\xe5\xab\x53\x5d\x78\x91\x26\xa3\x5d\x20\xaf\x38\xc4\x30\xb2\xb3\xd3\x45\x98\xf3\x16\xf6\x43\x2a\xab\x22\x31\x6b\x63\x86\x95\x43\x6a\x1f\x2d\x04\x10\x62\x46\xb0\x9d\xbd\x03\xc2\xd7\xa0\xc6\xed\xbf\xfa\x9b\x78\x24\x85\x99\x13\x62\xd2\x35", 155, { 0x67, 0x5f, 0x73, 0x7f, 0xcd, 0xad, 0xc1, 0x57, 0x5d, 0x11, 0x42, 0x81, 0xba, 0xac, 0xcb, 0x74 }, { 0x2e, 0x49, 0xac, 0x93, 0x81, 0x67, 0xf8, 0x04, 0x91, 0x57, 0xed, 0xec, 0x99, 0xe5, 0x7a, 0xf3 } },
{ "\xdc\xbd\x17\x3c\xf6\x1b\x88\xdf\xb7\xb2\x64\x63\x89\xc2\xbd\x6e\x38\xaa\x8d\x97\xd6\x4d\x1f\xc3\x57\x77\x8e\xb9\x1f\xf1\x5e\x56\x35\xb0\x90\x88\x2c\x74\xc6\xd2\xc3\x0a\x6d\x56\x0b\x49\xce\x50\x6d\xe4\x58\x22\x90\xf6\x49\x91\x15\xb3\x99\xba\x65\x6e\x33\xd6\xfa\x4e\xc7\xa9\xe1\xd9\x84\x1a\xd2\x76\x02\x17\xe2\xd3\x97\x2b\xd4\x5d\xbd\xbc\x66\x8d\x90\xa4\xe5\x54\xf1\xd8\xdf\x5f\x8b\xad\x97\xe5\x9e\x88\x88\x50\xf7\x64\x2c\xb0\x5f\x04\x6b\xd3\xb2\x76\x0b\xf0\xfd\x25\x2b\x11\x38\xf5\x8d\x8c\xea\xe9\x9e\x58\x8b\xa0\x2c\x0c\x18\x16\x13\xb3\x26\xff\x72\x39\x56\xc4\xde\x2d\x8c\xd5\x05\xdc\x49\xaa\x20\x2a\x33\xc2\x2e\xc5\x7a\xd1", 156, { 0xe7, 0xd7, 0x55, 0x52, 0x87, 0x69, 0x58, 0x2f, 0x33, 0x3a, 0xe4, 0x36, 0xba, 0x66, 0x51, 0xc4 }, { 0x2e, 0x7d, 0x5c, 0xfb, 0xe2, 0x2a, 0xc4, 0xaf, 0x40, 0xdc, 0xa8, 0x21, 0xd0, 0x3a, 0x17, 0x0e } },
{ "\x0b\x34\x50\x9c\x21\x77\xcc\x27\x7c\x91\x0e\x89\x8b\x45\xc4\xef\x24\xea\x7d\xe8\x2b\x71\x0c\xa4\xd1\xb0\xf9\x3a\xfd\x00\xa6\xbc\xb0\x04\x25\x51\x51\x1a\xc7\xc2\xb9\xf2\x60\x8a\x68\x70\xaf\x82\xe0\xb5\x79\x8d\xa0\xa7\x8b\xb7\x77\xea\xb8\x6d\x38\xee\x27\xb6\x88\xbe\xfa\xe2\x52\x11\xa9\x5e\xcb\xcb\x13\xd0\xf8\xc6\x84\x3c\x8a\x15\xab\xa9\x23\x29\x6c\x7b\x46\xb1\x69\x7d\xe6\x0e\xc0\xa6\x21\x83\xfe\x06\xd9\xf4\x18\x3f\xdc\x48\x08\xd1\xd7\x08\x50\x7e\xfa\x8b\xd8\x1f\x6b\x03\x1d\x08\x3e\xab\x42\xe9\x18\x22\x9e\x64\xee\xef\x5c\xa0\x7f\x2c\x72\x95\x28\x80\xca\xbb\xea\xe2\xf3\x68\xa6\x51\x33\xda\xdd\x45\xd1\x3d\xbe\x0c\x1c\x9d\x45", 157, { 0xc4, 0x51, 0xeb, 0x1a, 0x55, 0x65, 0x5b, 0xc2, 0x6a, 0xec, 0xdc, 0xd0, 0x2e, 0x51, 0x5a, 0xc9 }, { 0x4e, 0xc5, 0xcb, 0x15, 0xa7, 0x7a, 0x12, 0x94, 0x32, 0xa7, 0x94, 0xb4, 0x82, 0xf6, 0x91, 0xa2 } },
{ "\x3d\x3a\x67\x97\x48\x3c\x08\x5b\x15\x10\x2c\x46\x49\x76\x05\x01\xb5\x91\x52\x56\x99\x8a\x72\xd3\x73\x6c\x41\x4e\x0b\xcf\x4b\xd6\xc9\xfb\x66\x89\xe8\xc4\x9d\x99\xf4\x3c\xe2\x3a\xfc\x90\x90\xdb\x68\x88\x4d\xe4\xed\x3f\xa4\x7d\xed\xf5\x85\x8f\xc7\xc7\x68\xbd\x65\x78\xc8\xb6\x99\xf9\x2d\x6d\x19\x45\x19\x55\x19\x07\xec\x58\x67\x40\x1b\x97\x01\x51\x5e\x4a\x5d\xf6\x77\x26\x61\x27\x20\x40\x76\x4d\x51\xa5\xf9\x17\xc5\xb8\xf1\x9b\x30\xd4\x43\x16\x18\x43\x67\x95\xef\xc2\x71\x78\xd4\xa3\x92\xc2\x6d\x08\x3c\xdd\xd2\x1f\xfd\xfe\xa4\x97\xc8\xb4\x58\x59\x67\xdc\x07\xa6\x4f\xb5\x43\xa6\x98\x59\x13\xe8\xc8\xff\x9c\x9f\x46\xd7\x96\xcb\x16\xef", 158, { 0xee, 0x17, 0xc3, 0xf2, 0xa5, 0x5c, 0x11, 0x6e, 0x37, 0x33, 0x02, 0x38, 0x11, 0xb9, 0x13, 0x9b }, { 0xef, 0xd9, 0x14, 0xb2, 0x0f, 0x4e, 0x65, 0x5b, 0xe4, 0x80, 0x35, 0xf3, 0xb5, 0x36, 0x39, 0xc5 } },
{ "\x93\x62\xc6\x7c\x84\xfb\xc9\x7e\xc6\x84\x8c\x46\x6e\x2a\x4d\x8d\x07\x52\x43\x13\x0c\x3f\x3a\x1f\x40\xcc\x0a\x3e\x3b\x6e\x49\xea\x8b\x2f\xdb\x4d\x41\xcc\x0f\x61\x29\xb4\x28\x24\xe0\xea\xe9\x73\x48\x2b\x09\x2a\xb6\x73\xa6\xac\xd6\xbf\xdb\x71\x0f\x26\x7b\xb9\xc2\x84\x7c\x6e\x33\x22\x8e\x7e\xa6\xd5\x70\xc0\x7f\x5a\x3f\x5b\x5b\x8a\x3e\x9d\x85\x62\xf2\x30\x4e\xbc\x47\x6b\x22\x2c\xbf\x68\x3c\x69\x8e\xd0\x24\xe9\xd4\x78\x0f\x8f\xe6\x90\x40\xab\x0a\xec\x60\x96\x51\xda\x34\xff\xd8\x2f\x81\x83\x1b\x6a\x3c\x77\x3a\xf7\x20\xba\xb3\xfa\x57\xe7\x7a\x2e\x57\xa0\x1e\x7e\x54\x3f\xcb\xbf\xe3\xb3\x7b\xd8\x0d\x8d\xa5\xc1\x15\x86\x0c\x0c\x7e\x23\xbc", 159, { 0x94, 0xa5, 0x56, 0x18, 0x23, 0xa2, 0xeb, 0x84, 0x5d, 0xde, 0x63, 0x37, 0x53, 0x85, 0xea, 0x9b }, { 0xba, 0xdf, 0xe3, 0xdf, 0x1d, 0xfa, 0xa4, 0xad, 0x7c, 0xd0, 0x54, 0x9f, 0x52, 0x45, 0x17, 0x01 } },
{ "\xa6\x1d\x56\x9f\x2d\x63\x75\x40\x16\xdc\x9b\xe3\xc8\x44\x91\x59\x7f\xeb\xed\x45\xaf\xd9\xfd\x10\xdc\xff\xc2\x0f\x58\xac\xf1\xe8\x76\x01\x2a\xf0\x1d\x8a\x4e\xf9\xfc\x17\xe3\xce\x5e\xab\xed\xbf\xda\xbf\xe4\xf8\x87\x63\x78\x3a\x27\xf3\x8a\x2c\x5a\x08\x61\x18\x5d\xfd\x23\xc1\xc7\xcf\xd8\xcd\x2b\x92\x6c\x12\x6d\x9e\xd2\x1d\xb7\xc7\xeb\xb0\x62\x57\x22\x32\x59\x09\x2b\x52\xf4\xd8\x06\x90\x2d\x92\x32\x01\xfd\x4b\xfa\x5a\x5e\xdb\x17\x8c\xa0\x30\x79\xf7\x9f\xc9\x1f\x9a\xd3\xc1\x12\xc5\xf6\xe9\x49\x20\x66\x40\x06\xb6\x8d\xd5\x73\xc8\x43\x62\x66\xa2\x1e\x05\xf3\xa3\x7f\x41\x2f\xe0\x1b\x07\x63\x39\x36\xd7\x01\x4b\xa2\xad\xa7\x1d\x93\xbc\xae\x0c", 160, { 0x32, 0x0d, 0x43, 0x7c, 0xe1, 0x29, 0x1a, 0xd2, 0x80, 0x1c, 0x8b, 0x07, 0x81, 0xf6, 0x2a, 0xb1 }, { 0x6a, 0x99, 0xcf, 0x78, 0x08, 0x76, 0xc1, 0x99, 0xbe, 0x09, 0xb4, 0xf3, 0x7b, 0xd4, 0xaf, 0xed } },
{ "\xb2\xf9\x22\x16\x24\x14\x4a\x23\x28\xc8\xe8\x74\xa2\x1e\x68\xe8\x7a\x75\x65\x0b\xd5\xe7\x3e\x86\x92\xf0\xc8\xe5\x56\x34\xa4\xf4\xae\x1b\xa7\x6d\x9e\x34\x6e\xf1\x71\x0b\x01\x0a\xb9\xb9\x30\x41\x9a\xb8\x41\xac\xfb\x40\x74\xe5\xc3\xae\x89\x0b\xd4\x1e\xf6\x80\x52\x4d\xa2\x19\x93\xef\xe6\xc3\xb4\x72\xc6\xb7\xb7\x25\x51\x62\x3d\x47\x53\xab\xf5\xfc\xe0\x41\x64\xeb\x65\xbe\xe9\x12\xc5\xb9\x64\x48\xa2\x66\x68\xb4\xf8\x91\x9e\x23\x4a\x5b\x12\xfa\x6c\xa4\x35\xeb\x2d\x76\xbb\xda\x64\x8d\x47\x60\x40\x8e\x07\xc3\x8f\x27\x67\x5d\x49\x35\x17\x35\x69\xef\xa5\x6f\xfe\x3a\xcd\x6d\xe1\x1e\xc3\x6f\x61\x63\x43\x17\x47\x22\x6a\xe6\xbc\x35\x89\x43\xc9\x2d\x70", 161, { 0xc0, 0x2a, 0xda, 0x99, 0x23, 0xea, 0xfd, 0xf5, 0x09, 0x2f, 0x91, 0x53, 0x47, 0x59, 0x32, 0x1f }, { 0x6f, 0x89, 0x52, 0x79, 0x0e, 0x4f, 0xaf, 0x66, 0xce, 0xe5, 0xef, 0x8d, 0xf3, 0x86, 0x89, 0x8f } },
{ "\x89\x8b\x15\x25\x56\xf6\xae\x7f\xa0\x04\xc1\x39\xf3\xd1\x7d\xbc\x5d\x9e\xd8\xf9\x15\x82\x94\x71\x1d\xa6\xa1\xfd\x31\x87\x41\xae\x97\x73\x2b\xbc\x0a\x5e\xd5\xc9\x5a\xd8\x2e\x77\x94\x09\x7e\x48\xdf\xbd\x59\xdb\xe3\x71\x01\x9a\xd0\xac\xbc\xb3\x4b\x03\x5f\x5a\xf6\x9e\x01\x2c\x5a\xb2\x70\xc3\x0e\x05\x77\x1c\x17\x8c\x2a\x9c\x78\xc6\x9c\xeb\x7d\xf3\x89\x08\x99\x4a\x85\x61\x92\xc2\xcc\x73\xbd\x27\x43\x4d\x3b\x36\xeb\xdd\x1c\xd0\xc6\x18\xce\x23\x11\x01\x11\x4d\x57\xa7\x76\x57\xec\xc5\x25\x46\xef\x3d\x4d\x53\x14\x96\x8b\xca\x68\x86\xda\xe9\x35\x27\xfd\xc4\x27\xf5\xab\x82\x8a\xc7\x9b\xa2\x95\x65\x13\xfb\xcb\x53\xeb\x1b\xe6\xb8\x11\xd6\x97\x07\xec\x16", 162, { 0x12, 0xfc, 0x95, 0x7f, 0xe9, 0x3f, 0x9f, 0x2b, 0xd0, 0xfb, 0x1e, 0xd4, 0x47, 0x3e, 0xdd, 0x06 }, { 0xea, 0xf0, 0xb4, 0x31, 0x59, 0x6e, 0x8b, 0x63, 0x53, 0xb8, 0xbc, 0x08, 0x16, 0x40, 0xc1, 0x06 } },
{ "\x69\x2a\xad\x97\x98\xdc\x48\x27\xe1\x17\xc2\xa5\xe0\xcd\x74\x0b\xc5\xce\xb9\x94\x4d\x90\x3b\xc6\xb7\x1c\x18\xf1\xcb\x46\xab\x0c\x13\xc7\x62\x94\xa1\x23\x54\x06\x9c\xcf\xde\x5c\x02\x6d\x4c\x57\xec\xf7\x14\x71\x52\x12\xbf\xda\xc7\x09\xc5\x62\x41\xa7\xa3\xd9\x5b\xa5\x8c\x5e\xc9\x85\x1b\x5f\xc9\xf8\x2f\x7d\xdd\x80\x82\x69\x6d\x66\xe4\xf3\x96\x40\xef\x65\xa1\x68\x20\x93\xd9\x1d\xba\xd1\x99\x70\xe2\x1d\x00\x66\x5e\x18\x37\x28\xa0\x20\x54\x18\x6f\x42\x2e\x3b\xe3\xef\x26\x73\x86\x3b\x52\x3a\xfd\x2d\xfe\x89\xc3\x42\x63\x48\xf1\x2a\x86\x6d\x62\x70\x31\xa9\xdc\x15\x53\x58\x6f\xf5\x4c\x0c\x37\xe4\xee\x59\x56\x1e\x7c\xa9\x3a\x3b\x16\x05\xa4\x52\x50\xfc\x2f", 163, { 0x1c, 0xa6, 0x17, 0x6e, 0x87, 0x26, 0xde, 0xb4, 0xab, 0x3d, 0x8e, 0xd6, 0xa9, 0x9a, 0x94, 0x29 }, { 0xe3, 0x12, 0x8c, 0x8d, 0x19, 0x6a, 0x18, 0xa4, 0x94, 0xb2, 0x62, 0xeb, 0xb4, 0x96, 0x65, 0xdc } },
{ "\x1a\xd0\xfe\x8b\x65\x8b\x20\xb5\xe5\x95\x71\xc7\x11\xbc\x6d\xdd\xf6\x73\x21\x1d\x26\x25\xfd\x2a\x70\x66\xfd\x41\xe0\xf9\x40\x92\xf0\x9d\x3b\x9e\x89\x92\x3a\xaf\xf2\xf9\x46\x92\x9f\xbb\x5f\x99\xf3\x8c\x75\x41\xed\x5c\x54\xea\x66\x8c\xaa\x6f\x4a\x9b\x40\x60\x17\x64\x70\xe8\x3e\x95\x4b\x07\x03\xe3\x13\xb1\xed\xf5\x09\xaf\xf9\xb9\x36\x57\x6e\x52\x3b\x76\xaa\xe7\xae\xb5\x1b\x9d\x32\xe7\x43\x29\xdf\x94\x93\xbe\x1d\x41\xec\xa5\x1a\xb6\xa5\x37\x9d\x07\x44\xaa\x8c\xeb\x37\xef\x0c\x95\xd9\x2b\x55\xc1\x9d\x4f\x96\x68\x8e\xc8\xd1\x32\x7d\x7d\x98\x87\x6e\xee\xc4\xa6\xa1\xc7\x54\x49\x27\x15\x56\x4e\x5d\xa5\x11\x09\x47\xcd\x8f\x3b\xd8\xfa\xf7\x28\x85\xbf\x22\xb7", 164, { 0xc1, 0xd7, 0xbd, 0xc3, 0x99, 0xb4, 0x20, 0xb1, 0xb6, 0xd3, 0xca, 0x18, 0x75, 0x0c, 0x58, 0xaf }, { 0xf0, 0x07, 0x2a, 0x1a, 0x9d, 0x10, 0x70, 0x37, 0xfa, 0x46, 0x9c, 0xd4, 0xdf, 0x3c, 0xf1, 0xf3 } },
{ "\x63\x82\x90\xb8\x59\x48\x09\xb3\xe6\xea\x92\x8e\x77\x33\x2d\xae\x2d\xe7\xe0\x17\xa2\xff\x0e\xf8\xe8\x27\xcc\x83\x70\x35\x69\xd2\x46\x17\xfe\xdd\x4d\xed\xe8\xd3\x3b\xb3\x82\x71\x67\x3e\xf5\x65\xe8\x85\x36\xec\x01\xf3\x1b\xde\x5a\x0d\xb6\x66\x1f\xfe\xb3\x1a\xfb\xc4\x9a\x44\xdc\xca\xbf\x88\x7b\xf7\xaa\x88\x8a\xa3\xd9\x57\xf5\x81\x6b\x18\x4b\x32\x3d\xd6\x5d\x41\x69\x2c\x3e\x02\xa5\xb6\x55\x67\x7c\xc1\xe7\x92\xfe\xbc\xbd\x7c\xf7\x05\x9d\x33\xc6\x9e\xcd\xb0\xd0\x2d\x1c\x72\xd5\x59\x7f\x90\x95\x37\x2e\xa2\x99\x73\xf8\x74\xa6\x69\x9d\xd1\xa1\x6a\xe5\x50\x57\xf1\x1c\xe4\x07\x11\x40\x03\x76\x2c\x21\x1e\xe9\x19\x6a\x45\x07\x87\xa9\xbd\x9a\x23\x42\xc3\xed\xc0\x50", 165, { 0x02, 0x72, 0xe9, 0xd1, 0xf8, 0x49, 0x08, 0x67, 0xb3, 0xfd, 0x4d, 0xa7, 0xeb, 0xe0, 0x90, 0x2a }, { 0xe0, 0x30, 0x06, 0xa6, 0xbb, 0xf9, 0xce, 0xcc, 0x19, 0x4a, 0xc5, 0xf9, 0xbb, 0x10, 0x96, 0x00 } },
{ "\xa5\x1c\x01\x87\x59\x42\xb0\x84\x45\x4c\x4c\xdb\x18\x20\x83\xc7\x56\x38\x64\x22\x28\x5d\xf1\x7e\x71\xa4\xac\x05\xdc\x41\x40\xf0\x90\x82\x2f\xff\x4a\x28\xcb\x36\xe5\xb7\x59\xe4\x4b\x19\x1b\x19\x8a\x98\xc9\x7a\x71\x30\xd9\xaa\x5f\x8f\x6a\xb0\x4c\xb4\x95\x31\x53\xe1\x72\x79\x8b\x62\x5a\xa3\x1b\xc7\x45\x38\x77\x0c\x18\x9d\x5b\xce\x75\x65\x08\x37\x1e\x67\xc9\x95\x94\x37\x9e\xb6\x3c\xbd\x6d\xf7\x0e\xcb\x51\xd6\x85\x7a\x62\x17\xd3\x2d\x8c\x64\x62\xb0\xa4\x88\xc8\x04\xd5\x52\x1a\x54\x81\x3a\x69\x51\x64\x5a\x77\xad\xa6\x01\x4b\x03\x56\x84\xd9\xaf\x38\xa8\xb4\xdc\x2a\xd2\xab\x63\x4d\xbe\xdc\x1c\x4c\xbc\x5c\xe3\x46\x29\xd8\xc2\xc6\x6c\x19\xc5\xe8\x92\x06\x9f\x87\x36", 166, { 0xc7, 0x77, 0x33, 0xd0, 0x4c, 0x77, 0xe5, 0xb0, 0x24, 0xdf, 0xec, 0x87, 0x69, 0x67, 0xe2, 0x1a }, { 0x57, 0xa7, 0x7e, 0x77, 0x4c, 0x34, 0xb1, 0x1f, 0x9d, 0x47, 0xfb, 0x01, 0x7c, 0xed, 0x34, 0xa3 } },
{ "\xbe\xd1\x2e\x99\x0c\xca\xc8\x8f\x76\xc3\x28\xb1\x2e\x45\x09\x74\x39\xe7\x03\x74\x42\x83\xc3\x0d\x99\x87\xb2\x58\x9d\x9d\x72\xa3\xd2\x62\xf5\x0d\xb5\x95\x10\x53\x1b\xb9\x6d\xe8\xcd\xf5\x6e\xd1\xba\x86\x80\xcb\xb1\xee\x9c\x81\x21\xfd\x2f\xd5\x56\xd1\x0c\x59\x28\xdf\x70\xd4\x63\xb2\xe1\x8d\x5e\xab\xc7\xcd\x1a\x62\x26\x4a\xc3\xbd\x89\x92\x9f\x49\x5e\x1f\x76\xe5\x05\x36\x2d\xcf\x25\xa0\x56\xf1\x9a\xf8\x88\x62\x2d\xa2\x2f\xfd\x13\x2d\x92\x49\x4c\x97\xc5\x36\x7d\x2e\xee\xfc\x31\x10\x7a\x14\x77\x0d\x50\x24\x69\xc4\xb1\x8d\xae\xf8\xb5\x7f\x98\x29\xcd\xfc\x18\xd3\x43\x5a\x8e\x84\x83\x51\x08\xc0\x5c\xb6\xc1\xc5\x4e\x3e\x58\x11\xe7\x58\x74\x3e\x7b\x20\xad\xe7\x5f\x60\x1f", 167, { 0xef, 0xa4, 0x7e, 0x04, 0xec, 0xa0, 0x28, 0x94, 0xef, 0xca, 0xfc, 0xb4, 0xac, 0xcf, 0xf4, 0xc4 }, { 0x32, 0xb6, 0x38, 0xcd, 0x1a, 0x23, 0xd3, 0x95, 0xbf, 0x10, 0x1c, 0x58, 0x4b, 0x44, 0x2d, 0x0a } },
{ "\x30\x16\x40\xab\xa5\xbf\xb1\xb6\x7e\xc7\xd5\x96\xd0\x53\x52\x11\x16\xec\x79\xb5\xbf\xba\xa9\xad\x9a\xa9\x4e\x3f\xca\x42\x80\xc0\x2e\xcc\x6c\x56\x59\x18\x9a\x33\xaf\x03\x8e\xef\x5c\x16\xf0\xe9\x36\x14\xe7\x64\x29\x87\x6f\x15\xbf\x07\x3f\x50\xe1\x74\x77\xfc\xa7\x84\x17\x5a\xe2\x34\x3a\xcc\xba\x58\xfe\x83\xcb\x0c\x0b\x1e\x10\x66\xfc\x7e\xa1\xca\x7c\x69\xcb\x9f\xdd\x8d\x5e\x67\x3c\x2e\xab\xc8\x98\xbb\x4b\x68\xdc\x44\x5d\xb1\x6e\x7c\xda\x4c\x70\x4a\x0a\xa7\x73\xa0\xf0\xa4\x24\xf4\x78\x70\x99\x3a\x0c\xcb\xdf\xae\x27\x1b\x65\x4c\x13\xe6\x5e\x01\x4d\xf6\xa3\xef\xd1\xe3\xe2\x8c\x20\xeb\xb5\x07\xfa\xdd\xbf\x66\xdc\x0a\x7a\x74\x19\xfa\x23\xbf\x91\x21\x46\x8c\xf6\x0e\x61\x63", 168, { 0x92, 0xa9, 0x70, 0x3f, 0x9a, 0x3e, 0x69, 0x13, 0x7f, 0xca, 0x96, 0x0c, 0xdc, 0xcd, 0xbb, 0x34 }, { 0xb7, 0x0b, 0x41, 0xb4, 0xe4, 0x40, 0x48, 0x4e, 0x5d, 0xda, 0xe0, 0x11, 0xd7, 0xf7, 0xb3, 0xc1 } },
{ "\xca\x44\x3d\x62\x92\xf1\x68\x6c\xaf\x56\x50\xb6\x98\xdf\x11\x6b\x4c\x3c\x29\xee\x9a\xda\x6b\xdd\x00\xee\xfd\x43\xb1\xe1\x35\x58\x04\x41\xfd\xa0\xe9\xd2\xbe\xf4\x69\x41\x53\xe7\x02\x7d\x6f\xc0\x4e\x97\xe0\xa8\x44\xc1\x26\x83\x27\x6c\xc6\x35\x13\xfc\x0d\x93\x29\xb1\x32\xfb\xcf\x53\xfe\x80\x72\x96\xa9\x5b\x77\xa0\xa0\x56\xbe\x5b\x2b\x6f\xfb\x84\x7f\x7d\x95\xc3\x57\x9e\xa4\x75\x51\xaa\xd4\xd2\xb4\xd4\x85\xfc\x7e\x7b\x1a\x59\xec\x14\x14\x86\xc2\xaa\x75\xe5\x2a\x72\x28\xa6\xf2\xfe\xa0\x46\xe8\xe4\x24\x82\xb8\xb8\x9a\xee\x21\xe0\x5c\xf9\x32\x9c\x1c\x2a\xe3\xb6\x30\x7b\xe8\xe6\xd1\xc2\xc8\x10\xca\xd4\xd2\xf2\x19\x4f\x26\x52\x84\x91\x0f\xda\x83\x25\xf4\x78\x9c\xc9\x8c\xb6\x99", 169, { 0x58, 0xc4, 0x5f, 0x09, 0x40, 0xe5, 0x8a, 0xd8, 0xee, 0x64, 0x6a, 0x38, 0xc4, 0xc7, 0x16, 0x67 }, { 0xf6, 0x90, 0x5a, 0x55, 0xd9, 0x3c, 0xd2, 0xa6, 0xe3, 0x5c, 0x87, 0xb9, 0x80, 0x0c, 0xfd, 0x2b } },
{ "\x15\xc6\x8c\xbc\xfd\x7e\x1e\x97\x00\x4c\xe1\x5f\x8e\xad\x38\xf2\x1c\x55\xa7\x9d\x89\xfd\x91\x08\x58\xed\x38\x34\xbf\xa8\xaf\x5c\x67\x06\x58\xb1\xd6\xaf\xe3\xe1\x08\xb3\x70\x62\xbb\x59\x83\xe0\x13\x5a\x77\x32\xeb\x24\x88\xfc\x6a\xbb\x11\x88\xed\xb6\xc7\x19\x86\x59\xaf\x96\x84\x6b\x66\x13\xd0\xcc\x69\xf1\x09\xb7\x32\x35\x88\x7c\x84\x2d\xa7\x08\x79\x4e\x42\x83\xda\x9b\xd6\xff\x12\x8f\x2c\x06\xd4\x23\x68\xbb\x05\x75\x7a\xbc\xe0\x4b\x2f\x1f\x6d\xf1\x7e\x8e\x99\x17\x5c\xaa\x8f\xda\x30\x5d\xdc\xa3\xe5\x0e\xdc\x1f\xc0\xf3\x96\x9f\x8f\xcc\x6f\xaa\x5e\xe5\x2e\x5b\xdb\x22\x83\x36\xd8\xe4\x76\xe2\x98\xa0\x64\xf6\xc7\x02\x5a\x98\xf2\x79\xf5\x4c\xb6\x2f\xd1\xf0\x95\xbb\x66\x67\x03\xae", 170, { 0x38, 0x78, 0xf7, 0x6b, 0xf2, 0x87, 0x74, 0xfb, 0x77, 0xd4, 0xd1, 0xf9, 0x9d, 0xbb, 0xd5, 0x89 }, { 0xa3, 0xbb, 0x35, 0x97, 0x0c, 0x48, 0xbd, 0xce, 0x72, 0x9d, 0xbe, 0xc9, 0x04, 0x39, 0xc4, 0xf2 } },
{ "\xfc\xcb\x0b\xca\x97\x57\x39\xeb\x6f\xce\x28\x01\x72\xe8\xda\x8d\xaf\x81\x01\x26\x07\xe5\x77\x18\x88\x28\x70\x87\x0a\xee\x08\x97\xa5\x9c\xdb\x9c\x16\xc1\xf6\x50\x74\x3a\x3b\xa8\x7f\x99\x02\x03\xea\xe7\xf3\x16\x5c\xbf\x4d\x67\x06\x40\x68\x52\x3c\xdc\x18\x4b\x42\x77\x68\x6e\xcb\x19\x79\x3a\x5f\x1a\xc5\xcb\x19\x86\xa7\x4b\x4c\x44\x80\x94\x37\xcf\x8d\x1f\xf4\x72\x70\xfc\x82\x93\xbb\xa9\x08\x12\xea\xeb\x78\x3d\x04\x14\x48\x3e\x7b\x85\xb2\xfe\xa0\x4b\xe8\x31\x19\x4f\x10\xf0\x24\x99\x1e\x0d\x43\x2a\x3b\x60\x72\x42\xa5\x36\x97\x8a\xb1\xb7\x4e\x4e\x73\xbc\x59\x77\xd2\x57\x46\x62\x62\x4f\xff\xfb\xca\x18\xb9\x40\x0f\xbe\xbb\x1c\xec\xdf\x93\xd2\xfc\x18\x34\x6f\xe1\x03\x52\x70\x35\xc1\x29", 171, { 0x15, 0x1b, 0xd1, 0xec, 0xd5, 0xa6, 0xb1, 0x98, 0x35, 0x88, 0xdd, 0xb5, 0x33, 0x43, 0xeb, 0xe5 }, { 0x30, 0x7f, 0x2e, 0x91, 0xb1, 0x59, 0x82, 0x89, 0x84, 0x83, 0x49, 0x6f, 0x0d, 0xfb, 0x29, 0x51 } },
{ "\x50\xee\x93\xc6\x6a\x0f\xb6\xd3\xb9\x95\x3e\x44\x7c\x30\x32\x3c\x56\x85\xae\xb0\xfe\x91\x45\x73\x79\x83\x41\x55\xc4\x0d\xc4\xb8\x70\xc5\xfa\xa9\x99\xe3\x56\x54\xe3\x7e\xb6\xaf\x72\x54\x93\xa8\xc2\x12\x30\x41\x0b\x85\xc1\x8a\xbe\xd1\xe1\x63\xb5\xc5\xfb\xc1\xfc\xd7\xdc\xaa\xb8\xa8\xfc\x64\xa7\xce\x48\x36\xda\x53\xf9\x81\x7e\xb7\x2f\x7b\x6d\xe5\x75\x01\xf6\x88\x4d\x54\x5f\x42\x5f\x6c\xc7\xff\xf2\xca\x07\xae\x54\x4e\x43\xcc\x1e\x1f\xe2\x78\x69\x00\xcc\xa0\xfd\x70\x10\x4a\x1f\x13\x82\x93\xc6\x45\xbb\x01\x02\x34\x1c\x5b\xea\x55\x82\xad\x54\xdd\xbf\xed\xb2\x69\x62\x72\xb4\x85\x07\x42\x77\x39\x93\x50\x25\x32\xfc\xde\x5b\x35\x98\x42\x8e\x49\xf0\xc9\x20\xde\x9c\x59\x94\xa7\x11\x1b\x72\x6e", 172, { 0xfe, 0x64, 0x81, 0xab, 0xc5, 0xb0, 0x3d, 0x67, 0x80, 0xc1, 0x0b, 0x7d, 0x86, 0xa2, 0xc0, 0x54 }, { 0x57, 0x12, 0x3e, 0x1f, 0x18, 0xc1, 0xd1, 0xeb, 0x44, 0x56, 0xe2, 0xab, 0xe4, 0x33, 0x1e, 0x15 } },
{ "\x30\xd6\x6e\x30\x31\xe4\xdb\xf9\x0c\xa9\x2b\xbc\xde\xf0\x44\x22\x0a\xdd\x8e\x70\x30\x7d\xc3\xb9\x72\xe3\x2b\x99\xaf\x1b\x00\x8b\x6f\xeb\x7b\x1f\x4b\x15\x8d\xe3\x00\xb5\x24\x1c\x25\x26\xc9\x63\x41\xba\xec\x07\x6f\xeb\xeb\x78\x05\x84\xff\xf5\x5f\x11\x55\x59\x93\xea\x7f\xf0\x1a\x02\x96\x1b\xba\x58\x56\x40\x9e\x2c\x90\x6e\x03\x98\x42\xed\xb6\x5c\x03\xa8\x80\x14\xe5\xb5\xe8\x5d\x81\x00\x17\xa3\x5f\x33\x79\xe0\x7d\x50\xf5\x93\x03\x59\x0a\x28\xbf\x0c\x01\x64\xa5\x34\x37\x22\x0e\xb4\xec\x46\x39\x1d\x1f\x1b\x53\xea\xbf\xa3\xaa\xb3\x06\x0b\x7c\x9d\x16\x33\x55\x69\x47\xda\x03\x2f\xd2\xb0\xf8\x56\x0c\xa3\xb3\x6f\xe2\xdd\x91\xb8\x49\x43\xf3\xfa\x94\xef\xe2\xcc\x9e\xf6\x47\x57\x40\x71\x90\x23\x7f", 173, { 0x40, 0xc6, 0x9f, 0x90, 0x51, 0x97, 0x91, 0x7b, 0x9e, 0xab, 0x2e, 0x11, 0xeb, 0xc2, 0xdb, 0xd6 }, { 0xef, 0xc2, 0x2c, 0xfe, 0xf9, 0x7a, 0x8c, 0x00, 0x3f, 0x80, 0x07, 0x7c, 0xa1, 0x3f, 0x7f, 0x30 } },
{ "\x19\xd3\xce\x7c\x93\x6f\x91\xc1\x0d\xb1\xd0\x8d\xe3\x6c\xaf\x95\xe5\x51\xbd\x30\x81\x9a\xf8\xf7\xa3\x80\x3b\x21\x03\x4a\xd9\x52\x6f\xd8\x2c\xf9\xbd\xc9\x4b\xae\x88\xbf\xc2\xec\x25\x4e\x18\xc4\xbf\xe8\x4e\xa7\xb8\x0c\xe3\x48\x3a\xa2\x16\xde\xca\x0e\x95\x03\xa5\xbb\x08\x5c\xf7\x73\xee\xdf\x1c\x71\xc8\x9c\x33\x52\x6f\xcb\x38\xa7\x66\xa7\xf0\x35\x75\x0f\xae\xc0\xb3\x05\x79\xa6\xcc\x12\xb6\x55\xb6\x74\xb5\x98\x2a\x67\x7b\xc2\x75\x4b\xd0\x77\x21\x9a\x9f\x86\xe2\xd5\x76\xc9\x61\xa8\xb5\x9d\x0f\x88\x79\x50\x1a\x4b\x7e\xc4\x4e\x44\x8b\xd8\xf4\x83\xc4\x2c\x8b\xd0\xa1\x41\x5f\x26\x5e\xb6\x6f\xc2\x16\x45\x1c\x7d\x31\x11\x1e\x09\xa1\xe0\xa8\x0a\xb0\xa2\x44\xa7\x51\x51\xef\xcc\xbd\xfc\xad\xeb\x6a\xec", 174, { 0xea, 0xf6, 0x58, 0x37, 0x68, 0x80, 0xf2, 0xa5, 0xfc, 0x5f, 0x3d, 0xf0, 0xbc, 0xfd, 0x65, 0x75 }, { 0x21, 0xca, 0x35, 0x77, 0x76, 0x33, 0x9b, 0x82, 0x01, 0xfe, 0xa5, 0x4b, 0x39, 0x70, 0xbd, 0x02 } },
{ "\xe3\xd1\x33\x0d\x5a\x93\x49\x1f\x8e\xd2\x48\xd3\x2f\x59\xfa\x52\x1e\xdd\x01\x00\xba\x9b\x43\x57\xf6\x77\x9d\xac\x07\x8e\x15\x36\x91\x9c\xf0\x1f\x96\x44\x20\x0d\x44\xed\x91\xe8\x6b\xd7\xf4\x15\xbf\x61\xcc\x2b\x15\xd4\x2d\x6b\xfa\x82\x5f\xba\xa0\xb2\x36\x23\xaf\x91\x31\x00\x58\x7a\x0d\x09\x94\xfd\x65\xbe\xf9\xe6\x07\x26\xd8\x46\x93\x86\xb0\x43\x3e\x6e\x1a\x54\x5d\x0a\x2b\x8a\x61\x3d\x62\x41\x5e\xbd\xe8\x87\xdb\x22\xbe\x2f\x3a\x64\x0c\x8f\x96\x85\x35\xd1\x2a\x98\x57\x20\x3c\xb9\x27\x92\xf0\x0b\x41\x4c\xa4\xa9\x05\xd3\x7f\x44\xa2\xf6\xef\x1e\xe3\xa7\xf5\x68\x8e\xcf\x46\x04\x9d\x2b\x94\x91\xd9\xd0\x0f\x66\x67\xc4\x3d\xdf\x2e\xe9\x8c\xf6\x30\xbc\x25\x25\xdd\x0a\x19\xac\x81\xba\x90\x4c\xab\xb8\x4d", 175, { 0xd2, 0x72, 0x17, 0x4f, 0xb1, 0x9b, 0xe7, 0x3d, 0xe3, 0x31, 0xa7, 0xe6, 0x55, 0x4e, 0x5a, 0x08 }, { 0xaf, 0x85, 0x1f, 0x03, 0x77, 0x87, 0x81, 0xb7, 0x4a, 0x0e, 0xeb, 0xb9, 0x1e, 0xfc, 0x0b, 0x1c } },
{ "\xe3\x9f\x45\x41\xcb\xc8\x52\x38\x8c\x4d\xc0\x2c\x38\x07\xa9\xad\x66\xbe\x0e\xe1\x07\xe6\x5e\x2a\xce\xe1\x92\x6b\xde\x54\xf3\x33\x6f\x2c\x75\x35\x2a\xcf\x12\x6a\x33\xe6\xe9\x92\x75\x1b\xe2\xaa\xf8\x8c\x16\x95\xe7\x6f\x5e\xa3\x05\xb1\x68\xaa\x56\x17\xba\xcb\xa6\xce\x02\x60\x40\x8d\xed\x0d\xe7\xd7\xd4\xe6\x48\x7e\x9b\x57\xcc\xd3\x0f\xed\xdb\x21\xcb\x19\x54\xb5\x48\x1f\xcc\x20\xc8\x31\x37\xa0\x73\x44\xe2\xb8\x8d\x2a\x61\xa1\xa3\x4e\x00\xb5\xee\xbe\x8c\xd1\x88\x00\xbb\x00\xf6\x2e\xe7\x1f\x83\xe9\xa4\xff\x3c\x93\xe9\x83\x4f\xc9\x75\xcd\xc2\x96\xa7\x7c\x41\x57\xd0\xe7\x84\xb5\xe3\xb5\x35\x99\x6d\x4f\x50\x7e\x74\x69\xb2\x54\x66\x82\x8b\x68\x5e\x89\x7a\xdb\xba\x61\xaa\x0a\x87\x52\xc7\x92\x13\x18\x5c\x71", 176, { 0xcc, 0x97, 0x57, 0x9a, 0xae, 0x04, 0xa3, 0x36, 0x7d, 0x6d, 0x60, 0xa7, 0x5e, 0xa1, 0xd9, 0xe2 }, { 0x08, 0x08, 0xc7, 0xa8, 0xcd, 0x04, 0x63, 0x0b, 0x2c, 0x6e, 0xc3, 0x97, 0x0d, 0x85, 0x43, 0x98 } },
{ "\x90\x6f\x81\x7c\x88\x11\xd8\xe6\x00\x08\xf5\x28\x14\x38\xfe\xc3\x09\x45\x81\x30\x12\xa8\x3a\xd7\xda\x41\x38\x2a\xf3\xf4\xd5\x06\x93\x56\xc9\x59\x45\x44\x58\xa1\xed\xe9\x4a\x10\x69\xb2\xf8\xb7\x2f\x8e\x3a\xfb\x7d\x00\x2d\xf7\x44\x79\x71\x24\xd6\xd2\xd4\xe2\x26\xb3\x2f\x74\x71\x96\x2e\x66\x1e\x4e\xef\x3e\xca\x23\x67\x43\x9f\x4b\x0c\x0a\x48\xd6\x69\x3d\x2d\xbf\x10\x41\xee\x08\x86\x65\x4b\x35\x40\x16\x76\xea\xf6\x58\x4c\xf3\x19\x32\x22\x1b\x68\x8b\x4b\x9b\xa7\xe6\x5d\x56\x9a\x51\x11\x09\x52\x08\xa9\x1b\xac\xd2\xa0\x4f\xb7\x87\x44\x7d\xc0\xe4\x1f\xce\xae\xdf\x2e\x8f\xf9\xfb\xf5\xcb\x68\x7a\x52\x37\x21\x62\x8d\x55\x52\x21\x9f\x1a\x1b\x46\x7b\x58\xd3\xfb\xd4\xce\x29\x33\xdb\x8f\x54\xd1\x0b\x31\xf3\xa4\xe5", 177, { 0x72, 0x02, 0x9f, 0xd3, 0x17, 0x95, 0x1f, 0x7a, 0x73, 0xcd, 0xc8, 0xbc, 0x0e, 0xd0, 0x73, 0x1a }, { 0x03, 0x87, 0xc7, 0x1f, 0x68, 0x1c, 0x3e, 0x15, 0x49, 0x51, 0xe7, 0xab, 0x82, 0x47, 0x52, 0x3f } },
{ "\x5c\x94\x27\x62\xeb\x1d\xe9\x65\x2d\xce\xe1\xef\x85\xaa\x8d\xcc\x88\xa0\x17\xbb\x11\xde\x3c\xe7\xf2\x8b\xb0\x72\x37\xb1\xff\x88\x5f\xbb\xf4\xd5\x0e\x4d\xf0\x80\x24\x4c\x53\x4c\x0a\x9b\xec\xba\xc4\x1a\x40\xef\x00\xf0\x13\x52\xe3\x9f\x23\xa9\x4b\xd6\xe7\x2e\xed\x51\x9e\x4f\xe3\xc9\x15\x2d\xa5\x78\x6b\x48\x77\x67\xfa\x69\x89\x9b\x7a\x31\x5d\x3b\xcf\x05\xa0\xf6\xdb\x5e\xd0\x43\x45\x53\xb9\x90\xa3\xa9\xdb\x48\x3e\x21\x86\xbe\x5f\xfb\xb2\x6c\x1a\x25\x4d\x79\x39\x12\xdc\xe1\xd5\xad\xf1\x7d\x63\x03\x84\xc1\x8a\x72\x12\x99\x93\x6e\x0f\x59\x10\x11\xe9\xd4\x39\xa8\x8a\x54\x1f\x2a\xa5\x37\x19\x5c\x97\x9e\x84\x05\x42\xdd\x19\x57\xf8\x37\x4a\xb7\xf4\xf3\x5f\x2e\x9d\x91\x8b\x6b\x1f\xd4\x93\xba\xfc\x72\x23\xa8\x13\x9e", 178, { 0x0f, 0x61, 0x0f, 0x4e, 0xc9, 0xf8, 0x0d, 0x40, 0x24, 0x67, 0x40, 0x20, 0x0b, 0x67, 0x5a, 0x4d }, { 0x20, 0x31, 0xa1, 0x73, 0xc1, 0x60, 0x8d, 0x80, 0x79, 0xb8, 0xf2, 0xd6, 0x81, 0xb3, 0x86, 0xc4 } },
{ "\x9f\xca\xf8\x59\x0d\xbd\xd7\x48\xd4\xea\x00\xb1\x76\x41\xe0\x87\xcc\x4f\x47\x68\x62\xbc\x3d\xe4\x23\x3e\x60\x3d\xe9\xf9\x2d\xbf\xd5\xb0\x62\x9e\xe0\x1a\x37\xa7\xa2\x6f\x22\xf5\xbc\x8a\x63\x6c\xd5\xce\x20\x49\x3e\x19\xb4\x92\x46\xa6\x92\xed\xda\xa1\x29\x54\x0f\xbe\x52\xe4\x81\x29\xcd\xe6\xea\x4f\x5a\x60\xad\x5a\x77\xd7\xc2\xea\x81\xe5\x10\xa2\xd9\x15\x2e\xc6\x8e\xd4\x0f\x5c\x7d\x02\xa5\x60\xb4\x7d\xed\x93\xc0\x86\x46\x04\x58\xd0\xb9\x7f\x6f\xc1\x76\x36\xbb\x4f\x24\xf5\x8d\x43\xf7\x4a\x7f\xed\xa9\x73\x41\xb2\x00\x44\xc9\x9e\x74\x5f\x5c\x6c\xcb\x0c\x98\x2b\x9e\x3c\x27\x10\x34\xb9\x4e\x5f\x2e\x48\x28\x54\x23\xe3\x30\x63\x48\xd3\x37\x2e\x8e\x60\x0f\xab\xad\xeb\xff\x40\xef\xb1\xfe\xc0\xe8\x09\x62\xf6\x22\xc3\x73", 179, { 0xf6, 0x11, 0xc8, 0xa4, 0x7c, 0x5e, 0x6a, 0x79, 0x01, 0x49, 0x8f, 0x69, 0xa9, 0x60, 0x76, 0xbd }, { 0xf4, 0x2a, 0xed, 0x66, 0x1f, 0x62, 0x5d, 0xce, 0x93, 0x32, 0x51, 0x15, 0xe1, 0x4f, 0x3d, 0xd6 } },
{ "\x8f\xb1\x03\x7a\x3d\x54\xb9\x3e\xa9\x23\xef\x31\x08\xf6\x8e\xf9\xeb\x54\x03\x4f\xd9\x38\xf6\xb8\xe3\x25\x4b\x85\x61\x5b\xed\x23\x17\xe3\x53\xaa\xb9\x6b\x7f\x9e\x3a\x4c\xf1\x69\x8b\x40\xff\xdb\xd5\x19\x66\x72\x1b\xe5\xe2\x66\x0a\x31\x50\x1c\x20\x72\x65\x8f\xd8\xaa\x94\x7b\xc1\x59\x39\xa0\xa8\x2b\x49\xba\x03\xe5\x04\x28\x41\x0d\x30\x30\x99\xd7\x93\x16\x4d\x1d\x93\xa7\x27\xc8\x95\xd2\xff\x8e\x5e\xf7\xaf\xb2\x75\xc3\xfd\x75\xa7\xd2\x50\xb0\x10\xd8\xf5\x46\x0d\xc9\x85\x43\x21\x4e\x51\x05\xb5\xd2\x8f\xa4\x07\x7e\xe2\x87\xc7\x6c\x60\x3e\x36\xc0\x1a\x9c\x6b\x32\x13\xe1\x41\x50\x8a\xf4\xb8\x60\xa0\x05\x67\x0d\x46\x97\xc8\x0f\x8b\xc8\x5e\x01\xa3\x2e\x40\x44\x12\xb6\xa2\x07\x46\xb0\x75\x72\xe9\xea\x02\x98\xca\x61\x31\x34", 180, { 0xe2, 0x11, 0x69, 0x4b, 0x83, 0x94, 0x4a, 0x2d, 0xe2, 0xae, 0xce, 0x3b, 0x37, 0xf0, 0x75, 0x1d }, { 0x07, 0x2d, 0x8b, 0x87, 0x61, 0x39, 0xcc, 0x9a, 0xdb, 0xa7, 0x8b, 0xdd, 0x5d, 0x3d, 0x03, 0x3d } },
{ "\xdd\x2b\x4f\x42\x9a\xcd\x63\x4f\x68\xcc\xc1\xcf\x6d\x22\x5f\x76\xf1\x92\x9a\x21\xdc\xb6\x43\x5c\x48\xb8\xce\x22\xb4\x84\x9b\xf8\xcc\xfb\x62\x6e\x7f\x83\x67\xdb\x75\x7d\x07\x5f\xe1\xf8\xc6\xc6\xac\xaf\x18\xfe\xb3\x18\x16\xcc\xdf\x88\xca\xb9\x67\xd8\x2a\x0d\xc0\x82\x49\x19\xd2\x4d\x16\x2f\x8b\xd2\xe2\x54\x0b\x6f\xe6\xd9\x73\xcd\x14\x56\x0c\x31\x6f\x6b\x55\xad\x4a\xe7\xad\xff\x0a\xa0\x6e\xe3\x3f\x9e\x61\x22\xab\x21\x7d\x5d\xd3\x4e\x29\xc7\x35\x4f\x3b\xbe\x98\x70\x74\x4f\x1a\x78\xaa\x35\xbb\x1f\x56\xe6\xcd\xf3\x32\xd7\x97\xb1\x9c\x7b\xc0\xe8\xfa\xdd\x90\xa6\x3c\x38\xb3\x33\x84\xd1\x92\xbb\x4f\x22\x3a\xd1\x7f\x4d\x00\x93\xdd\xc3\x3f\xdd\xda\xe4\xfb\xf0\xf6\x85\xe7\x2f\x20\xd0\xb7\x77\x5d\x62\x70\xac\xc1\x1e\x82\x35\x2b", 181, { 0x01, 0x10, 0xb0, 0x83, 0x44, 0x58, 0x59, 0xb6, 0x09, 0x6a, 0x26, 0x49, 0xbd, 0x01, 0x6e, 0x1d }, { 0xdc, 0x7c, 0x19, 0x15, 0x34, 0xea, 0xb9, 0x72, 0x8d, 0x9a, 0x9b, 0x09, 0x00, 0x8e, 0xdd, 0xbc } },
{ "\xef\x65\xb1\xd7\x42\xe2\xcb\x0e\xa0\xdd\x51\x67\xd9\x17\xfa\x38\x37\xc3\xbb\x77\x2e\xad\x0d\x71\xcf\x89\xa1\xa9\x92\x8b\x08\xdc\x53\x24\x2f\xba\x70\xec\x42\x62\x44\xe6\x9a\x3d\xcb\x56\x9b\x13\xcb\xcd\x68\xf0\xcb\xaa\x49\x2c\xa4\x8b\x89\xce\x20\x18\x70\xa7\x70\x6b\xf7\x9b\x00\x38\xe9\x0e\x76\x60\x1e\x8c\x13\x05\xe8\xf7\x7f\x87\x9b\xab\xef\xcc\x3c\x6b\x5f\x5d\x49\xe2\x4d\x81\x45\x55\x1c\x72\x9a\xa0\xdf\x1e\x9f\x19\x5b\xff\xf1\x96\x48\xda\x5d\x2b\xdb\x42\x55\xfe\xad\x3e\x9f\xe8\xa1\x6d\x47\x9f\x3e\x87\x78\xb6\xb2\x95\x90\xf0\x59\xb8\x99\x87\x3a\xe9\xa7\x9f\x75\xad\xf3\xaf\x72\x79\xf1\xeb\x6c\x59\x04\x75\x5b\xee\x06\xd0\xad\x1b\x0b\x29\x91\xd5\xa9\x75\x77\x45\x06\x6d\x98\x05\xf2\xe1\xb4\x10\xa5\x25\xb1\x71\xf8\x3b\x9f\x8c", 182, { 0xf9, 0x09, 0x7e, 0x4d, 0x5c, 0xff, 0x96, 0x06, 0x4c, 0x1d, 0x4f, 0xc2, 0x30, 0x7b, 0xf5, 0x37 }, { 0x26, 0x1e, 0xe2, 0xc5, 0xcc, 0xeb, 0xf7, 0x53, 0xdf, 0x51, 0x02, 0xf1, 0x04, 0x37, 0xa5, 0xee } },
{ "\x10\xe6\xa4\x8b\x8d\x76\xa5\xb8\x0e\xd3\xed\x7c\x0e\x0a\xe6\xac\x2e\x88\x52\x7c\x13\x44\x47\xa1\xc6\x50\xd2\xc0\x28\x60\xf7\x17\xd8\x4f\x2c\x06\x6f\xa9\x78\xa1\xe4\xd4\x5c\xd7\x57\xd3\xff\x74\x9b\xf8\xab\xae\x5c\x33\xb8\x29\x0c\x5f\x82\x3e\xc4\x72\x0b\xcd\xff\x3f\xd9\x33\x85\xc2\x02\xe8\x8c\xdf\x71\xa6\xc4\x38\x3a\x09\x96\xb4\x5f\x39\x95\x97\x61\xae\xea\x37\x19\x01\x1b\x8f\xd0\x40\xb8\x68\x3b\x67\x33\x69\x61\xb2\xc0\x99\x33\x70\x9c\x12\x29\x11\x9e\xc1\x65\xf2\x09\xcd\xee\x7b\x73\xf0\x72\x3d\xe5\xb7\xdf\x78\x10\x6f\x7b\xe9\xe5\x1d\x04\x24\x13\x85\xb8\xea\x43\x90\xfa\x14\x7d\x3b\x79\x2d\x59\x9f\x6d\x9b\xcd\x4e\xf9\x32\x97\x1d\xb9\xa5\xd6\x6b\xda\xca\x77\x0d\xb1\x0f\x1e\x65\x1f\x34\xae\xff\xfb\xb0\x22\x96\xea\x57\x0f\x2a\x5d", 183, { 0x5f, 0x82, 0x74, 0x4c, 0x23, 0xc6, 0x83, 0xeb, 0x84, 0xeb, 0x54, 0xca, 0x8e, 0xb3, 0x00, 0x6c }, { 0x06, 0xb5, 0x89, 0xf3, 0x62, 0x3a, 0x3b, 0xdd, 0x24, 0xf3, 0xec, 0x3d, 0x53, 0x22, 0xd7, 0x7f } },
{ "\x40\xff\xfd\xd5\xa9\x4a\xc1\x20\xf6\x79\x68\x9d\xde\x72\x0a\xeb\xe9\x5a\xc8\x24\xca\xc5\x40\x1b\x28\x78\x09\xe5\x72\x94\x7f\x35\x62\x7e\xf5\x01\xda\x6e\x55\xcd\x32\x86\x28\x4b\x36\xd5\xea\xa1\x12\x7d\x33\x7a\x27\x21\x8e\xb0\xf5\x78\xf5\xcb\xfb\x53\x80\x57\x1e\x51\x77\xed\x7e\x3f\x90\xcd\xb0\x9d\xa1\xd7\xd1\x8d\x03\x18\xa0\x9d\x77\x1a\x53\x8c\x15\xe4\x3d\x90\x2e\x06\x1e\x55\x0b\x6d\xfb\x74\x53\x95\x7a\x75\xcc\xd2\x8d\x4b\xdf\x8c\xee\x40\xb2\x1b\x81\x03\xc8\xfd\x8a\x1d\x55\x69\xfd\xa0\x46\x85\xb5\x28\xbe\x8a\x85\xd8\xd2\xf6\xb2\x68\x83\xf3\x1f\xff\x4a\x7b\xc6\xea\x13\x9f\x20\x13\x3f\x05\xa8\x46\xcf\xfa\xe6\x54\x7c\x25\xc0\x8a\x5b\xba\x0d\x24\xad\xb5\x07\x08\x5e\x66\xe7\xf9\xc4\xd8\x58\x53\xb4\x54\x6f\xbe\x21\xe6\x62\x54\x0c\x97", 184, { 0xac, 0xb0, 0x95, 0x37, 0x0c, 0x76, 0x7a, 0xe5, 0x1d, 0x9b, 0x11, 0x03, 0xe0, 0xb8, 0x1f, 0x9b }, { 0xb3, 0x3c, 0xe7, 0xcb, 0x36, 0x65, 0xa7, 0xbc, 0x84, 0x49, 0x30, 0x07, 0xdb, 0x72, 0xd6, 0x97 } },
{ "\x36\x05\xc5\xba\x0a\x52\xd7\xd2\xb9\xaf\x10\x56\xf0\xe8\xfe\x75\x2f\x2b\xcb\x33\xbe\xca\xd6\x42\x5f\x07\x41\xd5\xa7\x0d\x97\x07\xad\xb7\xf1\x91\x07\xc3\x0a\xce\x01\x6f\x05\x23\xc1\xa0\x26\xc5\x83\xfb\xfc\x5b\x85\x84\x6f\xda\x42\x77\xc8\xa3\xbd\x92\x46\x60\xff\x0e\xb1\x36\x61\xf2\x18\x52\x60\x71\xec\x50\x59\x95\xbb\x31\x80\x4c\x38\x45\x98\x8a\x06\xf9\x74\xbe\x65\x1d\x5b\xfe\xfc\xb5\x51\x4d\x55\xfc\x51\xcf\x35\x6d\x7d\xa8\xf6\xa6\x45\xc2\x0e\x0f\xc2\x62\xab\x33\x7a\x55\x23\x81\x16\xc6\x35\x0d\x62\x5d\x73\x5f\x78\xd4\x5f\x1e\xf9\x10\xa8\x36\xa8\x55\x05\x67\x3a\x6a\xc9\x56\x40\x1e\xc7\x4b\xa7\xe0\x64\x69\x13\x04\xdc\xd6\x8f\x37\xd4\xfc\x38\x12\x1a\xe3\x29\xd5\x09\xd8\x4c\x9a\x31\xfe\x04\xef\x15\x4b\x46\x14\x90\xa8\xb3\x56\xaf\x77\xf3", 185, { 0x6b, 0x44, 0x43, 0x8f, 0x8d, 0x1a, 0x8c, 0xd8, 0xa3, 0x03, 0xed, 0x8d, 0xbe, 0xd5, 0x1e, 0xd8 }, { 0x7e, 0x40, 0x08, 0xa8, 0xab, 0xd2, 0x91, 0x2a, 0x67, 0xf7, 0x5b, 0xce, 0xd6, 0xf4, 0x15, 0x21 } },
{ "\xbe\x88\xa9\xff\x60\x8e\x4a\x2c\xcf\xa3\x4e\x15\x34\x84\x4d\xa7\x89\x74\xdf\x70\x9d\x5e\x49\x77\xcd\xed\x32\x88\x37\x90\x00\x5e\x6d\x3f\x90\xa5\xd0\xc5\x52\xad\x8c\x16\x24\xd9\xb1\x73\x6d\xef\xdd\xe7\xd7\x34\xfc\x26\x70\xaf\x08\xa8\x0d\x14\x84\xa2\x4e\x1f\xd6\xf6\x6b\xea\x71\xd0\x73\x26\x6d\x13\xcf\xf5\xac\x10\x58\x18\x82\x68\x87\xdd\xee\xc9\x63\xea\x43\xb1\x8d\x7e\x4d\x2a\x71\x54\xdb\xad\xbe\xf2\x56\x45\xa6\x6a\x3a\xc2\x7c\x68\x0e\xd3\xe5\xf8\x85\x68\xc3\xca\x31\x2c\xaa\xd0\x53\x6d\xc1\xa4\x09\xc5\xa7\xeb\x31\x40\x42\x72\xe9\x6b\x24\x06\xa0\xe2\x1d\x5a\x1c\xba\xef\xe2\x8c\x62\x15\x0c\x2e\xa6\xbc\x4a\xe3\xdf\x40\xed\x43\xf3\x07\xf4\x71\xe4\x6f\x2d\x92\xd1\xba\x22\x03\x83\xf6\x45\x3e\x31\x6d\xc4\x9c\x88\xfd\xd2\x87\xc7\x6c\x0e\x3b\x08", 186, { 0xf8, 0x13, 0x87, 0x18, 0x1f, 0xf4, 0x7b, 0xbf, 0x3a, 0xa7, 0xa9, 0x56, 0xbd, 0x0f, 0xa3, 0x5b }, { 0xee, 0x93, 0xc8, 0x85, 0xf3, 0x3c, 0x44, 0x94, 0x94, 0x6e, 0xc2, 0x65, 0x70, 0xbe, 0xc1, 0xb9 } },
{ "\x08\x2b\xda\xa2\x20\x8e\x5a\xbb\x48\xac\x5d\x93\xde\xb6\xef\x0d\xa4\xdf\x6a\x3e\x47\x08\xf1\x16\x00\x0e\xb7\x82\xc6\xf5\x2f\x40\xba\xa2\x5a\x5d\xce\x10\x0e\x0f\x1c\xc1\xba\x27\x79\x59\xd0\xee\xc3\xc7\x91\x2e\x19\xf1\xbd\x47\xde\x38\x64\x9a\x1b\xc1\x69\x95\xbb\x8e\x16\xf0\xee\x29\x1b\x5e\x1b\x42\x3e\x90\xea\x7b\x2f\x2c\x9c\xb2\x6f\xc0\x1f\x99\x6e\xa6\x2b\x7d\x95\x07\xc9\x94\x32\x48\xe4\x12\x2d\xd4\xcb\xcb\x73\x7a\x49\x23\x25\x31\x0e\x3c\xdb\xfd\xbb\x75\x5c\x32\x6a\x04\xb3\x58\x33\x63\xd3\x5f\x65\xfa\x2c\x87\xcd\x6e\xf2\x9d\x54\xe9\x12\x7d\x9a\x6b\x59\xe2\x08\x1e\x75\x70\xb9\xb5\xef\x8b\x05\x01\x1e\xbf\x44\x26\x0d\xd5\xb5\x4f\x9d\xef\x96\x94\x14\xb0\x5e\x9d\x9a\xcd\xb9\x9f\x74\x79\x9c\x34\xe6\x6d\x35\xf4\x3d\x21\x0a\x4e\xae\x33\x5e\x19\x20", 187, { 0x18, 0xa6, 0x43, 0x84, 0xfd, 0x90, 0x40, 0x32, 0x44, 0xe0, 0x6d, 0x93, 0x44, 0x62, 0x7d, 0xca }, { 0x3e, 0x6e, 0xb2, 0xa1, 0x56, 0x35, 0x7b, 0x53, 0xa2, 0x77, 0xc3, 0xa6, 0x0a, 0x08, 0xa3, 0x50 } },
{ "\xa0\xdd\xcc\xaa\x2d\x33\x9c\xbb\xbb\x12\xd9\x0f\xa6\x5b\x6c\xba\x76\xec\xfa\x48\x6b\x34\x69\xf3\x6d\xb0\xa9\xa7\x71\x66\xbf\x26\xb5\xe7\xb7\x4e\xa0\x6a\x62\x67\x4a\x67\x8e\xc1\x3b\x8e\xa4\x47\xe7\xa4\x89\x51\x84\x7c\x1b\x1f\xd1\xda\x6d\xdb\xa7\x32\x28\xbc\x26\xe9\x33\xc3\xae\x76\x29\xd2\xab\x10\x27\xdc\xfe\x98\xc3\x99\x0a\x51\xa4\x14\xf6\x85\x98\x1a\x70\x7a\x6d\x3e\x2a\x56\x99\x1e\xf4\x6f\xd8\x57\xe3\xdd\x29\xe4\x64\xc6\x63\x78\x52\xdb\xaf\x5b\x3f\x58\x09\x79\xe2\xf4\x62\x7b\x65\x98\xec\x6d\x00\x6d\x6d\x08\x42\xf9\xe3\xee\xcf\x9a\x67\x34\x14\x3a\x2a\xdb\xba\x89\x54\x80\xfe\xe4\xb1\x22\x52\x48\xa2\xa2\xe0\xb2\x1b\x9f\xd5\x8a\x30\x4a\xc7\x13\x80\x88\x42\x20\x33\x53\x8f\xc3\x61\x8b\x40\x8c\x3f\x30\xbb\x06\x3c\xdb\x19\x58\x5f\xac\xf3\x05\x21\x90", 188, { 0x75, 0xfb, 0xa7, 0x68, 0xc9, 0x1f, 0x94, 0x6a, 0x46, 0x0e, 0x44, 0x55, 0xcb, 0x02, 0x06, 0xd0 }, { 0xc3, 0xb2, 0xe9, 0xc3, 0x62, 0x7d, 0x07, 0x5c, 0x83, 0x48, 0x28, 0x0e, 0xb0, 0xe4, 0xa8, 0xf7 } },
{ "\x2f\xfb\x70\x10\x92\x05\x78\x0d\x56\xd8\xcc\x29\x51\x19\x32\x9c\x3a\xf4\x39\x39\x18\x08\xe5\xc6\x65\x1a\xfa\x8c\xf6\x7f\x8c\x3c\x75\xa0\x82\x46\x37\x1a\xff\x4c\xd6\xf6\xde\xe1\xcb\x34\xd9\xac\xdb\x8a\xa2\x9a\x4a\xd4\x43\x52\x4a\xf2\x7d\xe1\xb5\x8b\xdc\x7e\xd9\x5e\x7a\xce\x2b\x11\xc5\xc6\x4f\x2c\x8e\x13\x84\x9e\x26\x91\x7a\xf6\x91\x37\x5d\x9e\xfc\xc5\x39\x15\x35\x1b\xc4\x16\x97\x47\xfd\xdd\x7d\x6e\xdc\x1d\x67\x49\xf7\x5a\x5d\x84\x04\x89\x29\x8d\x41\x22\x64\x97\xfa\xef\x4f\xca\x55\x0e\x6c\x3f\x11\x8f\x92\xd7\x33\x90\x8e\x23\x8b\xfc\x57\xb7\x0a\x2a\x48\xa3\xb9\x74\x84\xb7\x6a\x44\xba\x5e\x23\x26\x5a\xda\x86\x57\x75\x82\x3e\xd2\x65\x26\xe3\xd3\xa4\x5d\x3b\x06\x55\x01\xfd\x86\xb2\xf8\xb3\xc9\x0f\xa4\x8e\xa9\xf5\x2a\x52\x7e\xbf\xee\x8c\xd5\x1e\x23\xa1", 189, { 0xa8, 0x61, 0x1d, 0x22, 0x24, 0x3c, 0xf4, 0x02, 0x57, 0xa0, 0xc2, 0x42, 0x9b, 0x88, 0x7a, 0x8c }, { 0x31, 0x27, 0x83, 0xbf, 0xd3, 0xa8, 0x2e, 0x2a, 0x04, 0x01, 0x04, 0x5a, 0xa4, 0xd3, 0x35, 0x5d } },
{ "\x0c\xda\x0d\x99\xfb\xb1\x12\x3e\x42\x3a\xe1\xf2\x86\x58\xbc\x72\x11\x15\x17\x05\x5e\x1e\x03\x19\xda\x5b\x47\x11\x45\x79\xc2\x21\xe0\x88\xed\x0d\xfe\x9c\x07\xa9\xa0\x31\xc6\x92\xfc\x26\xb1\x27\xcf\x03\x83\xb0\x58\xd7\xa0\x2b\x26\x2d\x5e\x5a\x44\x01\x3d\xec\x61\xef\xab\x7d\xc0\xa4\xe4\x69\x69\xaf\xba\xb0\x7e\x64\xb0\x9a\xe1\x62\x20\xfa\xc8\xce\x5b\x5a\x06\x10\x95\xf2\xe8\x7a\xbc\xb2\x58\xb7\xe8\x2e\x7a\xb1\x3e\x35\x7e\x3b\x69\x16\x4c\xea\xac\x07\x77\xec\x0f\xc1\x33\x58\x26\x96\x6a\xbc\x77\xae\x2e\xbf\x8e\xaf\x56\x93\x92\x68\x95\x01\x33\xf0\x14\x7b\xe1\xc9\x75\xa0\xd7\xd5\xa6\xdd\x0c\x17\xa6\xae\x5f\xdc\x5d\x20\xaf\xc5\x38\x27\xdc\xc1\xcf\xe2\x9c\xf2\x08\x85\xd3\x3b\xf4\x5f\x02\x45\x8e\x56\x3a\x08\x13\xee\x02\xfc\x43\x0c\xf6\xb5\x6d\xf5\xb3\x66\x7f\x42", 190, { 0x4e, 0xb4, 0xdf, 0x63, 0x22, 0x7a, 0xfd, 0x00, 0x26, 0x6e, 0xe6, 0x88, 0x36, 0x1e, 0xc5, 0xbd }, { 0x6e, 0xaa, 0x7f, 0x80, 0x5e, 0xc9, 0xb2, 0xa4, 0xa2, 0xa9, 0x3d, 0xda, 0xef, 0xf5, 0xd2, 0x87 } },
{ "\xea\x51\x19\x4d\x2e\xbd\x65\x42\xaa\x7c\xb4\x8a\xe1\x12\xf9\x85\x8b\x4c\x8b\x59\xe3\x59\x01\x06\xa6\x08\xb7\x19\xe7\xd0\x4d\x99\x57\x81\xcf\x1b\x1f\xcb\xf9\xfb\xca\xae\xac\x42\xb6\xc8\x48\x70\xb3\xb5\x90\x64\xa7\xc2\xcb\x07\x05\x10\xd7\x9f\x3d\x82\xe9\xfb\x3f\xfa\x72\xfb\x0b\xcf\x97\xa3\xb2\x03\x15\xd9\x3c\xd6\x79\xb6\xf4\x79\x5b\x4c\xf0\x65\x12\x26\x6a\x61\x5e\xe7\xf8\xf8\x13\x89\x62\x39\xc8\xaf\xec\x5b\x23\x64\x6a\xc5\x3d\x96\xe9\x0a\xd1\xd8\x99\x3b\xa4\x5a\x80\xe8\xc3\x6a\xc7\x6c\x92\xaa\x9b\x29\xfb\x5d\x8a\x04\x65\x8d\xb6\x92\x8a\x1e\xd0\xa6\x2d\x66\xaf\x75\xa7\x5c\xa0\xe6\x15\x43\xf5\xc6\x12\x0d\x3e\x47\x14\x60\x0f\x3f\x4f\x80\xe1\xe9\x56\x34\xaf\x8f\x95\xae\xcc\xa2\x6d\x48\x0b\x2a\x6c\x16\x5b\x24\x96\x21\xa8\x6d\xbd\x96\x6d\xd6\xae\x39\x29\x47\x10", 191, { 0x29, 0x9f, 0x78, 0xf5, 0xa7, 0xf7, 0x64, 0x83, 0x92, 0xee, 0x92, 0xda, 0xec, 0x0f, 0x30, 0xcd }, { 0x2a, 0xa4, 0x7a, 0x69, 0x06, 0xe8, 0xe5, 0xd9, 0xb0, 0x00, 0x0b, 0xf3, 0xb5, 0xa7, 0x96, 0x65 } },
{ "\x6d\x36\x33\xff\x43\x8f\xc1\x11\x30\x26\xa9\x35\x77\x6a\x4e\x3b\xb5\xb5\xdf\xe2\x75\x2d\xc8\x15\xe1\x88\xa1\x88\x7e\x65\xc9\xa2\x29\x6c\x48\x4b\xc4\xa3\xd3\x93\x21\xce\x4f\x08\x97\x79\xa8\x4a\x96\x1c\x1c\x2e\x6b\x20\xe8\x6d\x9f\x1d\xce\x12\x59\x6a\xb9\x44\x27\xd7\x1c\x7a\x50\xce\x43\x5f\xf6\x90\x5a\x40\xec\x96\x60\x1f\xd9\x51\x10\xf2\xcc\x80\xcc\x25\x76\x55\x44\x47\xad\xbc\xfb\xaa\x5e\x48\x76\x52\x70\xcd\x4d\xd3\xd5\x07\x2f\x30\xa8\x12\xb3\xeb\xdb\x7b\x45\x75\x6d\xc0\x0e\x02\x55\xc3\x10\x3d\xf8\x42\x2d\xee\x65\xeb\x0d\x25\x7f\x35\xa6\x96\xbd\x9c\xbb\x2c\x3c\x92\x59\x38\x64\xe4\xa6\x18\x1f\x66\xf0\x0f\x86\xcc\x0c\x22\x25\x9e\x6d\xcd\x08\xf3\xb7\x55\x36\xfa\x4b\x74\xd8\xca\x4b\x08\x33\x2c\xb6\xe4\xcb\x72\x52\x21\xee\x56\xd9\x1b\xe5\xba\xa1\xc3\xc2\x76\xa6\x9c", 192, { 0x42, 0x51, 0xce, 0x9e, 0x2d, 0xe1, 0xd9, 0x05, 0x29, 0x87, 0x3d, 0x33, 0x2e, 0xaa, 0x25, 0x82 }, { 0x19, 0x3d, 0xd0, 0x55, 0x95, 0xe1, 0xd6, 0x77, 0x57, 0xba, 0xc6, 0xc0, 0x3d, 0x4b, 0x62, 0x7e } },
{ "\x85\xbc\x59\x29\x3c\x94\x07\x16\x2b\x16\x39\xe0\xc8\x83\x36\xed\xad\x53\xc9\x36\xc9\x2b\x33\x26\x84\xa3\xd4\x3a\x2b\xad\xc1\xdb\x21\xad\xf8\x32\x94\x1d\x4a\x3e\x03\xf6\x10\x2b\xa1\x74\x06\x2e\xd3\x22\xcc\x2c\x10\x09\x86\x3a\x6a\x55\x94\x9a\x59\x3b\xf0\xa9\x1f\x0a\x5d\xfd\x93\x5b\x98\xde\x87\x7b\x9f\x86\x03\xc8\x17\x20\x20\xd9\x73\x2b\x56\x90\x55\x4f\x05\x85\xfe\xbe\xf4\x62\xbb\xad\xb5\xe5\xf7\x69\xba\x83\xd3\xeb\x4e\x0a\xfb\x2f\xda\x00\x03\x51\x9c\x87\x9f\x10\x0c\x66\xaf\x8f\xd4\xd4\xc3\x36\x89\x15\x36\x64\x24\xa3\x54\xd1\xdf\xb9\x15\xf2\xc8\x06\xe9\x97\x08\x4f\x57\xc5\x3f\x60\x04\x3d\x0d\xd4\xcb\x2f\x5d\x8b\xd6\x34\x41\x1b\xa1\x76\xa8\x09\x0a\x14\x85\x2a\x88\x6d\x14\x0b\xd1\x0e\xf1\x02\x6a\x7e\x21\xda\xb1\x15\xdb\x7a\x85\xd9\xae\x8b\xdd\x5c\x78\x2d\x28\x15\x88", 193, { 0x37, 0xeb, 0xe3, 0x8d, 0xa8, 0x48, 0xc4, 0xb0, 0x72, 0x7e, 0xaa, 0x09, 0xc3, 0x96, 0x5a, 0x34 }, { 0xd7, 0xec, 0xc2, 0x5a, 0xf6, 0xe9, 0xb4, 0x41, 0x4b, 0x91, 0x4f, 0x4d, 0xe5, 0x53, 0x87, 0x79 } },
{ "\xe2\x4e\x37\x3e\x00\xae\xe2\xc5\x00\x60\xf1\x4a\x20\xdf\x81\x57\xbe\x33\x08\xba\xed\x20\x2f\x87\x71\xb6\x3b\xc6\x65\xd9\xce\xda\x70\x1a\x4e\xcf\x2d\x3e\xaf\xb5\x5a\x11\x7d\xc3\x7f\x1e\x43\x27\x96\xc7\x3a\xc1\x83\xbf\x45\xff\xfc\x6b\x34\x60\xaa\x84\x28\x0b\x97\x9c\x2d\x53\xb6\x2a\x72\xa6\x01\xdf\xde\xa0\x68\xf0\x9d\x0b\x29\xe7\x18\x49\xa6\x51\x41\xac\x30\xe2\x28\xa6\x15\x81\xfb\x5a\xad\x80\xcc\x08\x76\xcd\x40\xf9\xb2\x22\xcb\x53\x56\x06\x8e\xf8\x1a\x54\xcd\x49\xd7\x49\x8c\xd0\x7b\x8a\xde\xa4\x5b\x98\x7b\x37\xeb\xa7\xd8\x5f\xb6\x8c\x32\x1d\xa8\x81\x68\xf6\xda\xa5\xcf\xf0\x6e\x73\xcb\x1b\x22\x4d\x4d\x75\x19\xf6\x90\x35\x67\x27\xfe\xf0\xb4\x53\x89\x29\x38\x90\x21\x30\xc6\x81\x8b\x6c\x42\xfb\x93\x5e\x53\x54\xe9\xcf\x78\x92\x11\xcd\x74\x5a\x2b\x07\x7b\x59\x47\x81\x86\x5a", 194, { 0x08, 0x65, 0x16, 0x91, 0xd7, 0x38, 0x80, 0xb9, 0x09, 0x33, 0xa5, 0x98, 0x2b, 0x0a, 0xa0, 0x83 }, { 0x5e, 0x7b, 0x6c, 0x0f, 0x28, 0x94, 0x7b, 0xd1, 0x16, 0xf8, 0x03, 0xc0, 0x83, 0xfa, 0x91, 0xb8 } },
{ "\xea\x93\x50\xaa\x78\xb4\xe2\x0d\xc1\xd9\x5f\xc0\x9e\xa5\x87\x55\xfa\xe1\x32\xf7\xb5\xb9\x93\x9e\xb3\xd8\xbb\xe9\x64\x8a\xd3\x0b\xd0\x99\x28\xea\x35\x80\x6b\x48\xe3\x93\x54\x12\xfc\xba\xca\x88\x6d\x73\x34\x83\xed\x01\x68\x4a\xf3\xe3\x90\x3e\x11\xe0\xef\x2e\x3f\x5b\x1b\x3e\x5d\x66\xed\x02\xd8\x3b\x5f\xe1\xcf\x43\x16\x61\x05\xa0\xf2\x30\xc7\xa2\xf5\x7a\x18\xb7\xf2\x50\x4c\xcd\x29\x4b\xe3\x0a\x33\x51\x8e\x96\xac\x4b\xdc\xda\xb0\xe3\xb1\xe4\x4f\x02\x28\x5f\xdc\x3d\xdb\x4b\x3c\x0f\x6c\x08\xed\x26\x5b\x9c\x1a\xa2\x6f\xa0\x64\x2b\x2c\x71\x05\x83\x35\x90\x68\x3d\x3d\xfd\x93\xb2\x15\x8f\xa9\x26\x15\x9b\xd0\xf5\x3d\x9e\x93\x8d\x69\xde\xfc\x97\x78\x53\x35\x44\xeb\x74\x1c\x9c\x06\x50\xae\x19\x6a\x7c\xfe\x7d\x74\x92\xb0\x37\xc0\x7e\x4f\xc4\xcd\x4c\xa1\x45\x77\x5e\x7b\x72\x25\xb9\x58", 195, { 0x5a, 0x4f, 0x38, 0x95, 0x0d, 0x88, 0x6b, 0x1a, 0xf5, 0x7a, 0xf3, 0x52, 0x4d, 0x62, 0x5d, 0xbc }, { 0x44, 0x75, 0x8f, 0x73, 0x1a, 0xd9, 0xd0, 0xe7, 0xf6, 0x95, 0x2a, 0xba, 0xa4, 0x64, 0x00, 0xfb } },
{ "\xc4\x68\xd2\x70\xda\x43\x98\xb5\x60\x3c\xe5\x59\xb2\xe7\x7e\x6f\x30\x4a\x7b\x90\x6b\x6d\x31\xbf\xec\xf1\xce\x30\xd4\xbf\x3d\x2c\x1c\x60\xbe\xbf\x4f\x14\x2a\xd9\x5a\xbd\x76\xd0\x19\x16\x9c\x0f\x4e\x71\xb3\x29\xfd\x8e\xf0\xc8\xdd\xeb\xdf\x48\x9d\x42\x0f\x6d\x96\xa2\xc2\xa4\xf0\xe1\xf0\xfb\x90\xd4\x29\xea\x21\x90\x73\x2c\xa0\x2e\x3e\x2b\xe0\x01\x1a\xcd\xc8\xfe\x9d\x7f\x94\x2a\x82\xda\x7b\x72\x00\xdb\x75\xbe\xf1\xf7\xac\xe9\xdc\x23\x5a\xdc\x1e\x17\x25\x5a\x29\xbf\x9d\xa3\xeb\xe3\xc4\xaa\xaf\x42\x90\x82\x7f\x6a\xb2\xed\xff\x6a\xf4\x36\xb8\x07\x01\x2d\x22\xa4\xcc\x9f\x38\xdf\xe2\xbf\x3a\x7e\x42\xe2\x71\xc2\x76\xab\xa9\x76\xd0\x56\xd5\xe3\x0f\xd4\x83\x5d\x3d\xec\x29\x08\xb0\x1c\x00\xf1\x48\x73\xfa\x26\xa7\x65\x1d\x24\x0a\x70\xdc\x93\xcf\xd2\x90\x0d\xf6\xd5\x1b\xf9\x65\x76\x7a\x61", 196, { 0xb9, 0x72, 0x9a, 0xd8, 0x89, 0x81, 0xf8, 0x5b, 0x74, 0x3b, 0xb5, 0x46, 0xc6, 0xd9, 0x7b, 0xdd }, { 0x51, 0x03, 0xa4, 0x00, 0x14, 0x89, 0xba, 0xf4, 0xb4, 0xf5, 0x94, 0x9b, 0x7c, 0x41, 0x1e, 0xdf } },
{ "\xd2\xd2\xf5\xb7\xc8\xcf\x44\xe1\x60\xb7\xd0\x69\x9d\x1a\x4b\xff\x27\x8f\xbf\x93\x93\x87\x95\x06\x19\x71\xdb\xb5\xf7\x1c\x0e\x72\x6a\x8b\x9b\xa5\x13\xba\x8f\xf7\xa5\x3b\xa1\x87\x07\x0a\xba\x10\x89\xa1\x4b\x13\x80\x2d\x57\x34\x3f\x02\xa0\xda\x70\xfc\x02\xf5\x9f\x1f\x55\x4c\xa1\x42\xa1\x44\x19\xda\x84\x2e\x52\x0a\xe3\x11\xca\xea\xa6\x86\x34\xe2\x90\xae\xd6\xb9\xc4\xf7\x86\x0a\xe4\x91\x18\xb9\x5c\x96\x9f\xb6\xb4\x72\x9a\xc5\xef\x77\x33\x0c\x13\x99\x7f\xa8\x88\x2d\xc4\x44\x16\xc8\x37\x8f\xde\x55\x27\x27\x25\x94\xc3\x6a\xd8\x9c\x3d\x45\x95\x1e\x91\x8b\xc6\x58\xc4\xf3\xb9\x94\x98\x72\x5e\x19\xee\x2e\xf5\x0b\x6c\x6f\xe9\xe1\x1d\x84\x8d\x62\x24\xeb\x19\x7d\xbc\x82\x39\x10\xa1\x46\xef\xd0\x55\x0b\x15\x1b\xa2\xf5\xd7\xda\xa2\x8d\x6f\x14\x03\xa9\xc1\x9a\x40\x21\x69\x82\xd7\x3d\x1b\xe2\xe1", 197, { 0xf1, 0x97, 0x2e, 0x6a, 0x32, 0xf8, 0x2d, 0x2d, 0xcb, 0x93, 0xe4, 0x8e, 0xe3, 0x97, 0x74, 0x3b }, { 0xa9, 0x9a, 0x1f, 0x50, 0x09, 0x79, 0x40, 0xb2, 0xc2, 0x97, 0x20, 0x94, 0x7c, 0xb5, 0xea, 0xfa } },
{ "\x37\x8a\xfd\x45\x7b\x03\x1d\x54\x4c\xeb\x1f\x55\xbc\x7b\x04\xb0\x05\x84\xca\x39\x65\xce\x1a\x2a\xf6\x3f\xd3\xda\x43\x30\x18\x8b\x4c\x2d\x6a\xa0\x34\x39\x81\xce\x67\x56\x84\xf5\x01\x31\x3c\xcf\x11\x58\x6f\xe9\xc5\xae\x08\xce\x5f\x7c\xda\x9e\xf1\xbb\x3c\xa7\x47\x6c\x9e\x2a\xd2\x1d\x86\xe5\x6f\x4b\x51\xc5\xca\xf0\xb8\xc8\xdc\x03\x8b\x9b\x7c\x5f\x1e\xfe\x3b\xb9\xe7\xd5\xd3\xb8\xe2\x67\x00\x9a\x3a\xa0\x59\xad\xd8\xa3\xaf\xcf\x7f\x18\x7c\xb0\x8b\x26\xd2\x8f\xcd\xc3\x69\x10\xe7\xae\xc8\x06\xaa\x6b\xc1\xa5\xfb\x91\x8d\x39\x7a\x81\xcd\xff\x9e\xef\x2d\x27\x8c\x6d\x94\x1d\xb9\xa3\x2d\xf4\xb0\xd8\xaf\x9f\x7e\x5c\x2a\x50\xfa\x3d\x38\x5b\x4f\xa8\xd2\xb1\xf9\xc6\x38\x55\xfb\x09\xa4\x25\x2b\x72\xff\x4e\xcc\x6d\xa3\x5d\x05\xef\x33\x6d\x23\x1e\x27\x8a\x37\xdd\x35\xf2\x62\x4a\x10\x4c\x59\xc6\x90\x24", 198, { 0x38, 0xe3, 0xd4, 0xaa, 0xa8, 0xa0, 0xf7, 0x13, 0x79, 0x0b, 0x0c, 0x9e, 0x5c, 0x30, 0x12, 0x6f }, { 0xe0, 0xd3, 0xb6, 0xd6, 0x95, 0x5c, 0x5e, 0x9a, 0x2f, 0x6a, 0x9d, 0x39, 0xb0, 0x86, 0x61, 0x3d } },
{ "\x84\xcb\xb0\xce\xf3\x5b\x21\x86\x2e\x4c\x6a\xb1\xcd\x89\x29\xeb\x9f\xf0\xd9\x6d\xb5\xf6\xed\x71\x51\xe0\xc6\x99\x4a\x14\xd8\xb1\x3a\x94\x46\x50\x4c\x43\x5f\x80\x91\x04\xf9\x5a\xf8\xbc\xe3\xb5\x79\xdf\xec\xe4\xa6\xf5\x98\xaf\x77\x68\x3a\x71\x0b\x41\x5e\xb8\x3a\x1e\xae\x0c\xbf\x4f\x6c\x80\x15\x20\x26\x79\x42\xb0\x20\x07\x95\x8e\x52\xc6\xd0\x81\x13\x01\xf0\xfa\xc2\x1e\x89\x34\xd6\x7d\xb5\x40\x31\xfc\x6a\x2a\x1b\xd6\x91\x89\xca\xda\x87\x25\x9a\x9a\xa4\x71\x99\xc8\x57\x9e\x4e\xcf\x23\x2c\x0f\xd6\x33\x5a\x41\x40\xdf\xbb\x8b\x90\x7a\x0b\x4e\xf5\x89\x12\x81\xf3\x91\xa1\xc8\x13\xdf\x8b\x05\x87\x82\x15\x14\x2e\xb8\xeb\x78\x28\x0f\xdb\x54\x10\x70\x83\x58\x73\x8d\x96\xf0\xdb\x0e\x85\x0c\x7e\x75\xd4\x4d\xe0\x79\x09\xa3\x7d\x93\x86\x1d\xae\x5f\xe4\x8d\x4e\xbf\x63\xd9\x1d\x56\x13\x44\x50\x7f\x11\x0c", 199, { 0x98, 0xb8, 0x13, 0x7f, 0x5e, 0x13, 0xaf, 0xbe, 0x6e, 0xd4, 0xee, 0x6a, 0x8e, 0x57, 0x57, 0x3e }, { 0x0d, 0x64, 0x90, 0x5e, 0x58, 0xbf, 0x47, 0xd0, 0x27, 0x9f, 0xa9, 0x41, 0x6e, 0x67, 0x2b, 0xbd } },
{ "\x17\x68\xf3\xb8\x3f\xcc\x90\x0e\xfb\xa8\xf8\xa8\xa8\x9d\x4a\x4f\x02\x68\xd5\x19\x42\xe0\xf5\xf6\x5c\xb7\xb4\x21\x7d\x44\xff\xcb\x1d\xbb\x5e\xa6\x3d\x99\xea\x64\xf3\x43\x86\x5e\x2f\x9a\xb3\x70\x4f\xcb\x5a\x7a\x82\xe0\x13\xc1\xb6\x04\xfd\x84\x08\x3c\xe7\x66\x1c\x91\x15\x8b\x9f\x54\x58\x07\x16\xa2\x36\xc8\xbb\x96\xc5\xb0\xeb\xd3\x93\x64\x9b\xae\xfd\xc4\xab\xbf\xa6\xca\x07\xdd\x3e\xd9\x64\xc9\xf2\xee\x75\xaf\xac\x54\xe0\xe9\x57\xe3\x3b\xe6\x97\x44\x3e\xe6\x70\xa4\x8a\xc1\x9f\x18\xfc\x48\x60\xb1\x2d\x69\x6e\x81\x4f\x27\xb6\xef\xc6\x09\xbb\xe1\xf0\x0d\x49\x64\x8b\x5b\x73\x91\x69\x45\x02\xc2\x46\xa2\x90\x61\x3c\x6b\x0f\xb3\x49\x92\xf8\x7b\xec\x9a\x9c\x01\x9a\x29\x05\x29\x74\x44\x27\x74\x2c\x1b\xe1\x26\xc0\xb4\xd7\xc2\xc3\x46\xf9\xfa\x76\x27\xde\x2a\xfe\x5d\x21\x8c\x33\xa4\xd7\x6a\xac\x01\x96\x20", 200, { 0x63, 0x22, 0x84, 0xb1, 0x76, 0xf7, 0x2a, 0x21, 0xbf, 0x19, 0x9c, 0x78, 0x67, 0x0a, 0x5a, 0xdd }, { 0x5a, 0x41, 0x08, 0x8b, 0xf2, 0xb6, 0x95, 0x54, 0xd4, 0x13, 0xec, 0x08, 0x7e, 0xdb, 0xfc, 0x0c } },
{ "\x2e\x6d\xc4\x9c\x49\xae\xa1\x88\x44\x2c\x44\xb6\x4f\x77\x3e\x1e\x62\xc0\xaf\xf9\x23\xc0\x39\x94\x6a\xb2\xb5\xe8\x0f\x0f\xf2\x50\x5e\x59\x24\xdf\xa4\xcf\x66\x34\x30\x80\x88\x6a\xfc\xb4\x96\xe6\x00\x24\xf9\x4b\x82\xb6\x82\x3a\x97\x3f\x45\x3d\xd4\x4d\x5a\xb2\xf8\x81\xd8\xcd\x2f\x69\xb0\xdd\x5d\x4d\xd1\xba\xa5\x70\xe5\x81\xd2\x53\x83\x74\xff\x41\x19\x3b\x46\xda\x75\x72\x0c\x1d\xa3\xe1\xce\x50\x6a\xe5\xbe\x7e\xc4\xb2\x77\x10\x13\x30\x0d\x91\x6d\x04\xc2\x06\xbb\x2b\xe7\x7f\x9a\xf3\xf5\x5d\x09\xbf\x95\xa6\xeb\xa5\x04\x71\xa3\xb2\x51\xcd\xaa\x50\xc6\x41\x5d\x92\x4d\x85\xc9\xe5\x27\x68\x09\x2d\xec\x7f\x68\xce\xbf\xd7\x9f\x30\x06\x17\x80\x27\x65\xf8\xdc\x33\x21\x67\xfe\x8f\x77\x98\x04\x86\x0b\xfd\xb1\x1c\xb7\xbb\xe2\xca\x72\x5f\xb0\x68\xf4\xe0\x4f\xe5\xef\xda\x41\x53\x32\xfb\x81\xa1\x1e\x6b\x3c\x00\x8c", 201, { 0xf9, 0xc3, 0x72, 0x25, 0xad, 0x1a, 0x74, 0xee, 0x02, 0x62, 0x2b, 0x32, 0xf8, 0x47, 0xe6, 0x45 }, { 0x89, 0x6b, 0xe3, 0xe6, 0x9f, 0x13, 0x33, 0x47, 0xb4, 0x8b, 0xc7, 0x83, 0x03, 0x78, 0xd8, 0xcb } },
{ "\x49\xea\x4a\x66\x71\xda\x95\x21\xc2\x06\x01\x08\x71\x96\x1e\xe7\xa1\x0a\xbe\xb1\xfe\x08\x48\x4c\xb3\x76\x07\xb0\x0f\x8d\x76\x58\xa3\xc4\x84\x3b\xcc\x5c\x16\x27\xca\x1d\x67\x51\x78\x98\x31\x0c\xcb\x71\x66\xbb\x19\xfb\x48\xb0\xb5\x0f\x48\xff\x36\xf3\x42\x9d\x0a\x62\x5f\x03\x01\x56\xf1\xa5\x69\x21\x5f\xeb\x89\xe6\xb7\x64\xb3\x68\x94\x77\x65\x78\x40\x59\xcd\xbc\xd6\x79\xc6\x1d\x3b\x75\x35\x87\x40\xf7\x2a\x8e\x6b\x81\x5c\x3a\xfe\xab\x64\x75\x4a\x57\x22\x92\xd3\xfe\x43\xfa\xaf\x50\xec\x3f\x65\xe6\x94\x72\x05\xf3\x48\xe3\x2e\x12\x3c\x89\x43\xc6\x4d\xee\x04\x9f\x94\xe4\x63\x06\xfb\x2d\x6a\x71\xfd\x98\x82\xa1\x84\xb4\xa9\xe5\x49\x29\x6d\xfa\x65\xd4\xae\x6b\xe2\x0b\xa0\x88\xb2\xcc\xff\x21\x32\x33\x6a\x62\x52\x20\x69\x4c\x76\xf9\x48\xc9\x40\x06\xdd\x5b\xb3\x7d\xa5\x8c\xcc\x86\x8c\x82\xc6\x44\x5f\xb3\xaa\xae", 202, { 0xba, 0xf3, 0x61, 0xa1, 0xf3, 0xab, 0x0b, 0x15, 0xd3, 0x10, 0xd4, 0x86, 0x66, 0xdd, 0x3c, 0x28 }, { 0x6a, 0x00, 0x68, 0x5d, 0xdd, 0x9c, 0xa6, 0x57, 0x1b, 0x5d, 0xf0, 0xe7, 0x71, 0xce, 0x24, 0x51 } },
{ "\xe4\xf5\xab\x8d\x30\x7f\x21\x4e\x17\xd4\x23\x53\x27\xac\x84\x95\x85\xdf\xbe\x94\xc7\x55\x44\x17\xfd\xfe\xb1\x85\xf8\xc5\xe9\xc8\x14\xf2\x0f\x66\x96\x11\x6a\x33\x3f\x32\x28\x16\x76\x15\xeb\x7b\x74\x76\xb9\xef\xb7\x7a\xff\x5b\x21\x90\x79\xb4\x0e\xf6\x5b\x90\xfd\xc7\x10\xba\xed\x84\x14\x0d\x74\x53\xf7\x5a\x66\x55\x42\xf3\x32\xff\x67\x9f\xcc\x0f\x77\xd0\x4e\x39\x5d\xa1\xce\x93\x02\xe3\xd3\x01\xa8\x95\x2d\x99\x05\xd0\x10\x80\x42\x9c\x30\xf4\x78\xb7\xf4\x34\x45\x00\x65\x4e\x31\x8d\xae\x50\x0b\xb5\x58\x7d\xef\x94\x7d\x6f\xe3\x6e\x55\x95\xbe\xa6\x8a\x28\xda\x5d\x1b\xa8\xa2\xee\x4a\x16\xf7\x60\xfd\x33\x11\x2c\x90\x1f\x8a\x58\x59\xae\x48\x01\xd1\xef\x78\xfa\x73\x28\xd8\x07\x9c\x7f\x7a\xe7\x3f\xee\xa4\xc3\x5e\x9c\x8b\xab\xa2\xdf\xb3\x44\x1d\xdf\xc1\x43\x97\x27\x0a\x16\x99\x24\xd0\xd5\x97\xd9\xb5\x4a\xd3\x36\x55", 203, { 0xe6, 0x5b, 0x6e, 0xf1, 0x9d, 0x3c, 0xc1, 0x30, 0x38, 0x06, 0xb5, 0xf1, 0x54, 0x82, 0x5b, 0x40 }, { 0xc0, 0x79, 0x73, 0x7c, 0x18, 0x02, 0x9d, 0xbe, 0x0e, 0xc8, 0x6a, 0x9c, 0x4e, 0xce, 0xf7, 0x75 } },
{ "\x64\x44\x4f\xc1\xa7\x3e\x86\x6f\x3a\x50\x83\x47\x2e\xb3\x64\xb0\x1e\x58\x80\x46\x3b\xf7\x10\x59\x89\x99\x6d\x77\x1f\xe9\x1a\xc8\x29\x04\xd7\xee\x8b\x30\x10\x11\xaa\x24\x5b\x13\xc9\x61\x8f\x0c\x8a\xe6\x62\x47\x29\x12\xa2\xa8\x44\x24\x94\x9e\x66\x3b\xea\x19\x03\x18\x29\xb5\x43\x05\xb0\x1d\xca\x21\x9f\xaa\x4c\xf6\xf1\x21\x90\x40\x77\x13\xeb\x9e\x09\x39\x4d\x41\xec\xee\x85\x0d\x8d\x1e\x86\x54\x64\x3a\xc8\x1d\xa8\x41\x61\x65\x89\x48\xe6\x96\xb8\xa8\x22\x19\x99\xb1\x39\x35\xad\x6a\x6a\x1a\x3d\xb9\x02\x0a\x8f\x80\xbc\x7c\x64\x9e\xe0\xfa\xde\x4c\x91\x01\x84\xf8\x64\x4c\xcb\xd3\xb2\x19\x35\xfb\x33\x6c\x2e\x03\x0b\x17\x40\x76\x48\x84\x51\xdc\x73\x3f\x1a\x7a\x66\x27\xeb\xa9\x00\x35\x5d\x74\x42\x15\xe7\x0d\xe3\x6b\xa2\x68\xf8\xbb\x22\x6e\xe2\xad\xad\x20\xca\xaf\xdf\x17\x1b\xbf\x2a\x5b\xd4\x42\x9d\x58\x9d\xb2\xc9\x0f", 204, { 0x77, 0xaf, 0xa3, 0x2a, 0xa3, 0xf8, 0x43, 0x33, 0x01, 0x16, 0x2d, 0xbb, 0x1d, 0x02, 0x88, 0xde }, { 0x5b, 0x7b, 0xae, 0xd9, 0x2b, 0xe0, 0x42, 0x4a, 0x4b, 0xf0, 0x0a, 0x1e, 0x70, 0x81, 0x23, 0x72 } },
{ "\x19\xd3\xf2\x71\xef\x75\x77\xae\xe5\xfc\xbb\xbf\xbb\x01\xd1\xa0\x48\x51\x59\xb4\xc5\x6b\xa4\xdc\x07\x43\x56\xef\x78\xfc\x28\x80\x48\x56\xa0\xd0\xec\x30\x7c\x99\xf7\xc6\x53\x3f\x25\x87\x88\x9b\x34\xc8\x24\xf2\xdf\xd6\x9b\x43\x77\x2f\xd2\x2d\x2b\xc1\xcd\xe2\xeb\x8e\x0f\x34\xbf\xf3\x47\x23\xaa\x73\x2a\x9a\xe4\xfb\x8f\xd4\xf7\xb8\xae\x78\xd0\xe6\x93\xb9\xe4\xe9\x0f\x93\x28\x4c\x26\x31\x70\x00\xc7\x13\x42\x4b\x51\xb1\xd9\x3d\xb4\x4f\x98\x6c\xd4\xaa\xd1\xca\x68\x21\x63\xad\x2a\xa6\x0a\x58\x76\xaa\xf1\x74\x13\x4e\xfb\x58\x86\xa8\x7a\x29\x5d\x6a\x09\xd1\xab\xf7\x6b\x38\x0a\x3d\x30\xcb\xe7\x23\xc0\x59\x3f\xcd\xe7\x85\xcd\xb6\xdd\x47\x78\xc7\x44\x7c\x66\xa6\x7f\x6a\xfe\x90\x50\xda\x25\xad\x12\x3d\x38\x15\xcc\xea\xb4\xeb\x3b\x29\x7e\x14\xc7\xa8\x6d\xc9\xbb\x01\xaf\x3a\x35\xd0\xe4\xb4\x6e\x78\x6d\xab\x5a\xe7\x1d\xdc\x29", 205, { 0x00, 0xf6, 0x95, 0xad, 0xc5, 0x33, 0x8c, 0x32, 0x3b, 0x8c, 0x80, 0x5f, 0x1e, 0xe5, 0x71, 0xcb }, { 0x48, 0x0a, 0x50, 0x84, 0x05, 0xab, 0xc9, 0xa9, 0x49, 0x24, 0x1c, 0x4b, 0x42, 0x1e, 0xc7, 0x61 } },
{ "\xc3\xe6\x73\x02\x70\x80\x1c\xc5\x87\x9e\xb5\x13\x3c\xcf\x99\x0f\x06\x82\xd6\xf4\x67\xb9\x80\x77\xa6\xc3\x18\xe6\x79\xfd\x1b\xc3\x5f\x0a\xe7\x6e\x01\x47\xfe\xb5\x22\x53\x57\xcd\x17\x17\x19\xe5\x12\x6a\x86\xef\xaa\x1f\x29\x34\x42\x18\xb8\xf6\xf6\xb4\x16\xe3\xd1\x1c\x9c\xe8\xb7\x32\xcc\xab\xb8\xc9\x27\x59\x93\xc5\xa1\x5b\x1e\x63\xda\x76\x3e\x18\x34\x2e\x56\xf8\xcb\xad\xf2\x30\x03\xab\x0a\x83\xec\x40\x83\xa8\x01\x02\x27\x8c\x28\x4e\xeb\xfa\xd1\x8b\x24\xe2\x00\xac\x28\x42\x0c\x7a\x36\xd4\x65\x27\x4c\xb2\x8a\x65\xfa\xd4\x8f\x2c\x3c\x97\xdd\x2d\x12\x13\xe9\xf5\x1c\xa6\xb8\x04\x78\x2c\x1d\xa6\x69\x14\x68\xb9\xd8\xea\x2e\x95\x3f\xea\x18\x6f\x1f\x01\x51\xe6\x24\x9a\x65\x63\x52\xbf\x2f\xd0\x73\x14\x1d\x7b\x6a\x5d\xb7\xd7\xfe\xb3\xc0\x71\x1f\x38\xf4\xfc\x00\x24\x37\x78\x41\xf3\xa3\x7a\xf1\xf9\xd9\xb2\xfe\xe3\x22\xe3\x76\x28", 206, { 0x35, 0xe0, 0x98, 0x00, 0xad, 0xd6, 0x2b, 0x06, 0xb4, 0xf7, 0x8d, 0x75, 0x2c, 0x90, 0x84, 0xe8 }, { 0x32, 0x84, 0x45, 0x05, 0x48, 0x21, 0x2a, 0x76, 0x72, 0x71, 0x14, 0x75, 0x11, 0xd2, 0x19, 0xc0 } },
{ "\x34\x0b\x2d\x20\x0a\x86\x9e\xdb\x23\x58\xe2\x80\x37\x58\xab\x11\x1a\xea\xc2\xbe\xca\x54\xf4\xa4\x15\x8a\x00\xe0\xd1\x14\xda\x27\x13\x4b\x32\xed\x8b\x0c\xb4\xcf\xae\x5b\xd5\x8c\x1b\xe6\xbf\x4b\x12\x25\xe1\xb1\x66\xf6\xf9\x89\x3a\x58\xee\x74\x0a\xfc\x3b\xc3\xce\x9a\x98\xe7\xf0\x07\x50\x8b\x14\x52\xce\x9e\x13\xa3\x33\x65\x62\xdc\x46\xa9\x23\xf6\x59\x64\x7e\xc9\x5b\xc7\x19\x7f\x39\xcd\x58\xf1\x9e\x06\xff\x9c\x6c\x5a\xa1\x21\x68\x7c\x1b\x8c\x27\x99\x20\x0e\x4b\x52\x3d\xe7\x93\x35\x31\x9a\x18\xb0\x8e\x26\x34\xcf\x2c\x44\x94\xb6\xf6\xe8\xf3\x4d\xac\xf8\x21\x87\xa9\x1d\x23\xf4\x4c\xf8\xaf\xbb\xf8\xe6\x8d\xad\xe8\x7d\x5a\xa9\xca\x30\xeb\x92\xcc\x4a\x11\x86\xa9\xfa\x4e\xa8\x6f\xfb\xe6\x6b\xa3\x96\x27\xd2\xcb\xdf\xc6\xe4\x81\xaf\x0e\xdd\x6b\x4b\xd7\x53\x59\x52\x4d\xe7\xce\xe5\xe0\x73\x2a\x33\x60\xc1\xc1\x4e\xa8\x77\x8c\xf3\xbd", 207, { 0x88, 0xc5, 0x42, 0x5c, 0x23, 0x98, 0x39, 0x49, 0xdd, 0xa3, 0xb1, 0xaa, 0x76, 0x02, 0x15, 0x94 }, { 0x19, 0xbe, 0x9a, 0x96, 0x21, 0xa7, 0xfd, 0xce, 0x71, 0xfc, 0x0f, 0x0a, 0x80, 0x8f, 0xa5, 0x4f } },
{ "\xd2\x26\x4b\x3e\x3e\x76\x17\xdb\x51\xc2\xef\x6b\x71\x39\x8c\x60\x06\xfe\x2f\xff\x62\x85\x9a\x21\x3e\x57\x9c\x69\xcc\x2d\xee\x5d\x8f\xdd\xb3\xcc\x17\x9c\x6f\x75\x7e\x76\x92\x48\x5f\x8d\x7f\xef\xc8\x4a\x35\xcb\x4c\x6d\xc9\xdb\x52\x7c\x0d\xd1\xcf\x57\x3c\x40\x05\xe2\x80\x20\xf3\x04\x38\x30\x53\x0f\x48\xa4\x62\xf4\x90\x18\x1c\xee\x73\xc6\x10\xf4\x9a\xe8\x7f\xfe\xe6\x6b\x74\x10\x35\x88\xe5\x62\x43\x00\x63\x3c\xdb\x49\x43\x2c\xdd\x2e\x79\x6b\xa0\x6d\x3c\x98\x5b\x99\xdd\xf3\xee\xe9\xa2\x06\x3a\x3b\x4c\xfe\x18\x3d\x7b\xe6\xc1\x86\x43\x64\xd3\xe3\xcc\x38\x37\x24\x68\xce\xc1\xbd\x1f\xf1\xe9\x49\xd0\x34\x66\x96\xf3\x6d\x2f\x02\x2a\xd7\x46\x1e\x62\xeb\x28\x0c\x5a\xaa\x09\x2b\x9b\xf8\xb8\x65\xf9\xbe\x23\xa4\xf0\x82\xd0\xa6\xfe\x6d\x61\xee\xe6\xbc\x42\xa0\x1e\xb9\xcd\xee\x15\x8a\x30\x45\xd4\xa7\x32\xfc\x09\x29\x82\xdc\x5d\x78\xe9\x1b", 208, { 0x89, 0x42, 0x2f, 0xc7, 0x09, 0x90, 0xf4, 0x41, 0x25, 0x82, 0x0d, 0x53, 0xf2, 0xbc, 0x49, 0x08 }, { 0x6c, 0xfd, 0x28, 0xc4, 0x40, 0x56, 0xfd, 0x72, 0x10, 0xe5, 0x35, 0xc8, 0xda, 0xeb, 0x9c, 0xee } },
{ "\xb0\x45\x3d\x25\x20\x64\x56\xb7\x79\xa5\x03\x9f\x9c\x2c\x55\xfe\x1a\x9c\x4e\x3d\x48\x94\x19\xbf\x35\xf4\xb3\xb5\x8d\x06\xed\xa4\x23\x6e\xc1\x08\xc2\x13\x36\x7e\x90\x74\x3f\x6c\x65\x5c\x8f\x92\xa7\x5e\x4f\x35\x30\x23\x2c\x58\xd2\x67\xbd\x64\x2b\xf2\x09\x04\x9c\x1e\x12\x4b\xe9\x93\xe6\x9c\xa4\x83\xdd\x5e\xa3\x9a\xde\x98\x6a\xaf\x0d\x24\xe7\xfd\xab\x0d\x4d\x2a\x5a\x17\xe0\xe4\x2e\xc8\xab\x05\x0c\x58\xdc\x7f\x4d\xa4\x47\x40\x1b\xc1\x23\x04\xf5\xbc\x88\x01\x1d\x83\x37\x65\x06\xb0\x9e\x6d\x34\x57\xd1\x6e\x6a\xaf\xe1\x6c\x85\x97\x0c\x8f\xbe\x0d\xa9\x3f\xb8\x8a\x4b\xfd\x83\x0b\x88\x26\x32\x31\x16\x05\x65\xc4\x1d\xc5\x9f\xbb\xbc\x2f\xb8\x3b\x7e\x88\x9c\xbb\x86\x35\x14\x7b\x85\x67\x0e\x89\xea\xb8\x63\xe2\xcd\x18\xeb\x8c\x10\x4f\x7f\x7f\x6d\xda\xc4\x2b\x9a\xc2\xc7\x04\x9d\xdf\x2e\x8f\xcd\x2b\x8a\x8b\xe9\x17\x17\x42\x79\x2e\x5b\xca\x6c", 209, { 0x32, 0x06, 0xab, 0x7b, 0x4a, 0xee, 0xe1, 0x31, 0xa8, 0xc7, 0x54, 0x75, 0x36, 0xe7, 0x2b, 0x6a }, { 0x8c, 0xdd, 0x74, 0xa1, 0xeb, 0x3b, 0x5c, 0x0f, 0x70, 0x24, 0x57, 0x95, 0xb0, 0x8b, 0xd5, 0xb0 } },
{ "\x85\xfc\xd3\xf1\x37\x35\xac\x9a\xf8\x25\x30\x94\x40\xba\x2b\x35\x88\xe2\x40\x8a\xc3\x39\xcb\x12\x7d\x0f\x72\xc8\xfd\x6a\x5e\x8a\xe0\xe9\xbb\x53\xc3\xdd\xb9\xf2\x56\x6d\xfe\x4e\x0b\x49\x53\xf3\x47\x0e\xc2\xb5\x23\xef\x08\x2b\x53\x65\x66\xc2\xb4\x65\x21\x53\x16\x58\x4d\xf3\x13\x45\xac\xf4\x81\x9c\xa4\x1d\x3d\x39\x74\x5b\x81\xa4\x93\x17\xb4\xf6\xf9\x3f\xc3\x03\x74\x88\x3e\x86\x5b\x8c\x19\x21\xde\xc6\x1d\x1c\xfe\x71\x9c\x48\x0a\x65\x18\x93\x97\x40\xed\x66\x60\x9f\x8c\x7b\xcb\x97\x5e\xfd\x17\xc2\x5b\xa3\xd5\xed\x27\xfe\xf7\x00\x7c\x90\xd9\x4c\xda\x75\xfe\x8a\x87\x01\x0e\x44\x43\xe4\xad\xa1\x6a\xa6\x65\x76\x90\x19\x68\x9c\xfa\x46\xea\xc5\x2c\x68\x5e\x96\x45\x61\xed\x5e\x8e\x28\x73\x3e\xb1\x4e\x10\x04\xcf\xe8\x39\x6e\x20\x55\xc8\xf5\x52\xc6\x20\xe1\xb2\x85\x09\x9e\x2e\xd9\xf2\x45\xa8\xa2\x4f\xe2\xdb\xbc\xb6\xe3\x4b\x51\x6a\x88\x8d\x62", 210, { 0x29, 0x1a, 0xea, 0x5b, 0x9a, 0xba, 0xd3, 0xe8, 0x7e, 0x90, 0xaa, 0x94, 0x68, 0x73, 0x16, 0xb7 }, { 0x19, 0x04, 0x41, 0x1d, 0x3a, 0x9a, 0xb3, 0xc6, 0x2d, 0x5a, 0xbe, 0xd5, 0x13, 0xf7, 0x01, 0xf2 } },
{ "\x84\x4c\x8a\x6b\x9f\x95\x97\xd4\xfc\x6f\xa3\xd0\x36\xae\x93\x4e\xe1\xc9\xa7\x89\xa9\x7e\x5b\x7e\x72\xc2\xf3\x88\x27\x05\xa0\x0e\xf0\xc7\x85\x74\xef\x49\x1f\x69\xa2\xda\x16\x95\x43\x46\xd4\xc2\xa5\xff\x60\xef\xc2\x7a\x5d\xbf\xb9\x26\xe5\xf6\x70\x05\x57\xde\x1a\xeb\x27\x99\x92\xa6\x8b\x14\xe6\x55\x63\xab\x70\x0b\x2e\xfa\x27\xbd\xca\x42\x6c\xbc\xae\xed\x23\x31\x7e\x24\x28\xf3\xfb\xd7\x5f\xf1\xeb\xbf\x01\xd5\x3f\x89\x5e\x43\xf0\x6b\x29\x9e\xed\xf2\xa6\xe8\xb3\x3a\xdb\x03\x06\xec\x65\xf1\x7c\xa8\x91\x5b\x3d\xc5\x91\x2f\xe7\xf4\x29\xaf\xa5\x36\x9d\x93\xd8\x32\x4f\xcd\x2c\xbd\xaa\x03\x14\x38\xff\xf1\xf3\x2e\xa0\x22\xb9\xaf\x81\x00\xf2\x0c\x27\xe2\x51\xc3\x43\x32\x54\xe8\xe9\x70\x2f\xf1\x88\x2d\xa4\xfc\xf7\x40\x9a\x73\x28\x0d\xef\x23\x55\x25\x48\xa3\x78\xa7\xb5\x7d\x9e\xe0\x27\xba\x14\x6d\x33\xd8\x6a\x19\x81\xaf\x6b\x19\x23\x9f\x90\xb2\xd2", 211, { 0xf9, 0x5f, 0x44, 0x1b, 0x15, 0x91, 0xc1, 0xee, 0x38, 0x4d, 0x89, 0x76, 0x89, 0xcf, 0x57, 0xdd }, { 0x9d, 0x7f, 0x09, 0xd6, 0xc5, 0x38, 0x63, 0xe6, 0x45, 0x4d, 0xd5, 0xe6, 0xf1, 0x10, 0xd2, 0xbd } },
{ "\x7b\xa4\x7c\x0b\x3e\xc8\x13\x4d\xd0\x2f\xcc\xfd\x88\xbd\xa2\xe4\xc8\x90\x14\x1c\x63\x3c\x67\x2d\xbe\x5d\xd8\xf6\x36\x36\x63\xfe\x17\xf1\xd6\x39\xa8\xb0\x33\xba\x02\x5f\x96\x01\xf7\x3c\x6e\x1a\x99\x88\xcd\x44\xe3\x41\xe0\x02\x5a\x3c\x7e\x4c\x00\x40\x1b\xe0\x7b\x5b\xbc\x40\xe9\xc1\x5d\x6b\x16\xb7\x65\xd4\x55\x0a\x6e\xbf\x68\xb6\x02\x33\xec\x68\x36\x31\x6d\x7d\x4d\x32\xe5\x8c\x88\x0d\xc0\x83\xb7\xa0\xae\xb3\xd2\xc9\x96\x88\xa1\x5f\xcb\x58\x34\x19\xc5\xcf\x6f\x63\xbf\x79\xfc\xbc\xe8\x32\x2c\x8b\x94\x13\x2b\x2d\x74\x99\x92\xed\xbb\x2b\x2c\x44\xa2\xd2\x99\x15\xf8\x72\xed\xbf\x07\xe2\xae\x1f\x89\xfa\x4e\x44\x1d\xf8\xf7\xe1\xbb\xca\x5b\xc0\x13\xdc\xac\x13\xfb\x11\xe2\xe1\x85\x29\xce\xfe\x7c\x5b\xee\x4a\x76\x05\xab\xa5\x06\x19\x37\x06\xd2\xfb\x5f\xb4\xca\x36\x2d\xe6\x06\xaa\xb1\x7b\x79\xd1\x27\x65\x7e\xbf\x33\x02\xcb\xeb\xec\xb2\x1f\x6e\x43\x2b", 212, { 0x31, 0xb5, 0xf9, 0x6b, 0xd8, 0x6c, 0x49, 0x33, 0x94, 0x44, 0xa8, 0x6d, 0xed, 0xdf, 0x2a, 0xd4 }, { 0xbf, 0x59, 0x94, 0x3a, 0x3a, 0x35, 0xbe, 0xb7, 0x10, 0x78, 0x4b, 0xb8, 0xa4, 0xbb, 0xb3, 0xf6 } },
{ "\x84\x41\x5c\x4f\xf2\xb6\xe1\x06\x21\x40\xa8\xd6\xa6\xbd\xef\x3e\x97\xeb\xd3\xd0\xac\x34\x8f\x58\x2d\x99\x15\xa7\x7b\x23\xaf\x0b\xab\x19\x2a\x61\x44\x3a\xdc\xab\x46\x23\xd2\x86\x59\x63\xd1\x76\xb8\xb0\xc5\xd1\x76\xde\x3f\x78\x29\x33\x49\x2d\x85\xd2\x50\x94\x28\x3c\xd0\x44\x52\x78\xa6\xff\x7b\xdb\xb2\xb6\x40\x14\x32\x3e\xe3\x11\xe6\x6f\x8b\x49\x3e\x1a\x88\x66\xce\x17\x48\xb0\x66\x89\xb9\xab\xfe\x89\xbf\x95\xc0\xe4\x32\x56\xa2\x78\xe5\x61\x49\x76\x80\x99\xd8\x39\xbd\x05\x0d\x75\x8a\xc0\xb8\x08\xef\x6c\x89\x91\xd1\xbe\xb3\x2b\x3a\xa0\xc6\xe9\x00\x66\x87\x38\x9a\x4a\xfc\x33\x8b\x17\x66\xd6\x5e\xf6\xd1\xf3\xd8\x32\x15\x17\xeb\xfd\x91\x5b\xcd\x2d\x32\x1c\x44\xa6\x89\x23\x39\xed\x68\xda\xf9\x3f\x87\xbf\xe5\x21\x51\x3f\x67\x5a\x55\xcb\x0b\xd6\x33\xc1\x5d\xe5\x41\xf1\x0d\x5b\x6c\x4f\xb1\x19\x77\xd7\x44\x1c\x29\x55\x20\xf7\x67\xf7\x44\x44\x5a\xbb\xb3", 213, { 0xf0, 0xc7, 0x75, 0x58, 0x9d, 0x46, 0x80, 0x13, 0x40, 0x1c, 0x93, 0xde, 0x00, 0x93, 0xe0, 0xd1 }, { 0x94, 0x37, 0xd4, 0xe8, 0xee, 0x70, 0x26, 0x48, 0x18, 0x91, 0xb6, 0xc2, 0xc7, 0x12, 0x47, 0x85 } },
{ "\x96\x55\xab\xad\x90\x2f\xc7\x4d\x7e\xb0\x30\x73\xdb\x23\x8d\x8b\x82\x9f\xf9\x4e\xd6\x96\xcb\x73\x2e\x77\x09\x24\x7e\x61\x45\xa3\x6d\x5a\xb8\xd3\x9e\xab\x6a\xe5\x0e\xd2\xac\xbf\xe8\x97\x78\x2a\x25\x3f\x59\xf3\x5e\xd8\x28\x88\xa2\x1f\xa1\xde\xa4\xa0\xfb\x2c\x9a\x11\x32\x77\x5c\x4e\x95\xd6\x28\x44\x8e\x79\x5c\x58\xfd\xb1\x77\xc5\x5f\xd3\x5b\xc1\x88\xbd\x71\xf2\xc4\x8f\x76\xf0\xff\x2b\xbe\xd0\x48\xff\xa6\x80\x03\x51\x76\xd9\x97\xa0\xca\x14\x3e\xe8\x83\xc8\x3e\xcc\xcf\xb1\xb7\x7b\x7e\x49\x31\x00\xf2\x0f\xaf\xe9\x54\x4f\xdc\xab\x90\xd0\xe7\x37\x64\x35\x1a\xd2\x43\xcc\x34\x91\x5e\x5e\x8f\x6d\x18\x95\x60\x4f\x68\x31\xdf\x3f\xfe\x75\x4f\x8e\x68\x67\xba\xb2\x7c\xca\x49\xfb\xff\x57\x2a\x7a\xa0\xfd\xa7\xef\x96\x49\xab\x21\xe9\x3a\x67\x74\x11\xcd\xcd\x83\x69\x07\xd1\xe7\xf9\xe9\xcd\x44\xb4\x78\x3b\x89\x9b\x39\x79\xd0\x30\xcc\x70\xe9\xb9\x5d\x86\xe4\x81\xee", 214, { 0xe0, 0x72, 0x5c, 0x5f, 0x73, 0x9c, 0x87, 0xc0, 0x5f, 0x79, 0x9b, 0xc7, 0xfe, 0x66, 0x7b, 0xe6 }, { 0xa6, 0xaa, 0xf0, 0xca, 0xce, 0x43, 0xb1, 0x1d, 0x35, 0x34, 0xab, 0x3d, 0xbe, 0x46, 0x5d, 0x2d } },
{ "\xf7\x44\x5a\x5c\x42\xe2\xbb\x9e\x2f\x0a\xf8\x82\x8a\x6a\xd6\xe0\xff\x4b\xf8\x39\x6c\x6b\x14\xe3\xfa\xe0\x87\xe1\x04\x3e\xa2\x0a\xcb\x32\xc5\xb1\x6e\xf0\x55\xbb\x3e\x1f\x4e\x2c\x09\xab\xa2\x60\xc3\x71\x05\x14\xcb\xd6\x86\xa0\xc5\xf2\x98\x27\xd1\x02\xb3\x83\xa8\xf1\x6a\xa6\xdc\x7b\x21\xa4\xad\xac\x27\x09\xed\xaa\xd3\xb8\x3a\xd1\x08\x75\x2d\xdb\x43\xa7\x4e\x63\x43\xdd\x22\x3d\xe3\x2f\x60\x1c\x46\x28\xb8\x0a\x8d\x92\x10\x51\x67\x5d\xe9\x44\x30\xe9\x5f\x5e\x35\xa5\x62\xe1\x5c\xc6\x7e\xd4\xa8\x77\x4c\x45\xbb\x9a\x9d\x68\x7b\x93\x3b\x47\x51\xca\xb9\xd1\xc1\xa7\xb7\x2e\x49\x07\x09\x25\x0a\x29\xd2\xec\x79\xf1\x74\x51\xb4\x10\x8b\x29\xdb\x9d\x41\xa9\x42\x45\x8b\xec\xb5\xd5\xd7\x55\x69\x84\x77\x7e\x8a\x31\x83\xe1\xc6\x2b\x3e\xb2\xd6\x2a\xbf\xe3\x44\xe7\x66\xc1\x87\x5d\x36\xa8\x73\x0b\x6b\xee\xc2\xbd\xd4\xcc\x75\xe4\x38\x34\x2c\x08\x4c\x1b\xa8\xf1\x0e\xba\x44", 215, { 0x9a, 0x9a, 0x4f, 0x73, 0x5c, 0x13, 0xa4, 0xd4, 0x9a, 0x49, 0x2e, 0xbe, 0x9a, 0xbb, 0x5d, 0xc4 }, { 0x01, 0xf4, 0x0f, 0x4e, 0x58, 0x86, 0x4c, 0x56, 0x3e, 0x3b, 0xd2, 0x91, 0xa0, 0x43, 0x76, 0x82 } },
{ "\xd4\x13\xb2\xc9\x75\x9c\x24\x0d\xb6\xea\x81\xb6\x81\x37\xe3\xc2\xf9\x7b\xfe\xcc\x5f\x0a\xa1\x1f\xc7\x9d\x95\x15\x7b\xef\x69\xc5\x01\x7a\xf0\x64\xb8\x45\x97\xfd\x43\xff\x5f\xbe\x98\x68\x1b\xfe\x41\x29\x85\xd2\x59\x5c\x86\x94\xed\x81\x7d\xff\x45\xab\xd9\x3b\x36\xe4\x5d\x1b\xe7\x6d\x7b\x5b\xfc\x2e\x19\x1d\xe7\xde\x7b\xf8\x79\x13\x1d\xb5\x5c\x3c\xd0\x88\xef\x92\xf8\xc9\x83\x57\xea\xa2\x6b\x76\x48\xcd\x2f\x23\x65\xc3\x40\xa0\x2d\x45\x2b\x8a\x20\x0d\x6b\xb6\xb0\xba\x6b\x83\x39\x0c\xd3\xf1\x1b\xae\x3b\x2f\xe5\xb5\x55\xa4\xd8\xff\xff\x7c\x72\xd2\xf0\xbc\x81\xc2\x0e\x66\x2f\x86\x7a\x14\xbb\x8a\x1c\xc6\xe9\x8f\xa7\xa6\xc4\xdc\x93\xc8\x46\x9d\x38\xd0\x76\xd7\xff\xb0\x37\xe1\x57\x0a\xa5\xe2\xd3\xcf\x71\x73\x4f\x5d\x04\x23\x14\x54\xbb\x65\xf1\xd2\xdb\xf0\x7e\x68\x3b\x36\x50\x52\xd1\xb3\xde\x6a\x1f\xb0\xe6\xfc\xb7\x16\x7f\x71\x11\x30\x26\x5d\x71\x4b\xaa\x13\x9e\x55", 216, { 0xb8, 0x4e, 0x26, 0xab, 0x83, 0xca, 0x15, 0x65, 0x3b, 0x3d, 0x01, 0xda, 0x70, 0x6f, 0xa4, 0xa8 }, { 0x8e, 0xae, 0xf6, 0x51, 0xc4, 0x3d, 0x88, 0x3c, 0x94, 0xc7, 0xc9, 0x6e, 0x60, 0x5b, 0x34, 0x77 } },
{ "\x7c\x28\x80\x7f\x07\x2b\xdc\x7b\x2a\xbf\xab\x0d\xd1\x81\xe0\x70\x06\xb7\x76\x87\x5e\xbf\xa2\xf2\x27\x6d\x1b\x80\x0b\xa9\x69\x37\x2b\xac\x51\x92\xa8\xa7\x4f\xe4\x7d\x2b\x25\xb3\x77\x3a\x8d\xa2\x33\x2d\x48\x9c\x1a\xb7\x95\x49\x7d\x91\xb1\x0c\x74\x0b\x09\x10\xf8\x39\x3f\x08\xcc\x41\x45\xe4\xba\xde\x22\x6c\xd7\x16\x01\x3d\xd9\x97\x06\xb5\x61\xb9\xb9\x72\x96\x97\xd3\x4b\xbc\xdc\x90\x41\xe0\x80\xef\xf9\x8e\x3a\x58\xde\x7c\x06\x4d\x01\x8b\xf6\xbb\x8c\x14\x24\x60\xc8\x4f\x23\xf3\xf8\x52\x80\x57\x6d\x32\xf8\xb1\xc6\xf3\x7c\x1c\x6b\x9e\xae\xbc\x3d\xba\xc1\x2f\x27\x91\x47\x3a\x88\x00\xff\xf9\x04\x3d\x8d\x92\xf0\xe9\x81\x95\xd8\x24\x21\xd2\xdf\x63\x4e\xfc\x04\x41\x0f\xeb\xb0\x1e\xfe\xfa\x27\xb8\x1f\x7d\x92\xf2\xfb\x00\xa3\xf8\xbb\xc3\x20\x00\x51\x96\x6a\xea\xc4\xf6\xc8\x85\x57\x0a\xcb\x80\x5b\x56\x39\xaf\x21\xfe\x5b\x30\x9c\x32\x11\x9f\x2b\x6e\x09\xa4\xb1\x64\x33\x65", 217, { 0x9e, 0xfd, 0x8c, 0xb0, 0x38, 0x3c, 0xba, 0xcf, 0x7e, 0xd6, 0xf4, 0xff, 0x0f, 0x71, 0x7a, 0x06 }, { 0x82, 0xae, 0x6a, 0x89, 0x29, 0x0b, 0xc6, 0x10, 0x19, 0xb5, 0x90, 0x7e, 0xd2, 0xe6, 0x9c, 0xdd } },
{ "\xdb\x34\x3f\x47\x0a\x60\xd0\x19\x1e\x1e\x4b\xf6\x23\x33\xef\x20\xaf\xcd\x51\xeb\x84\xd6\x56\x4f\xe3\x8b\x9c\x18\xc0\x03\xf8\xf1\xfd\x83\x05\x42\xa2\x1c\xe6\xea\x52\x61\x18\xcd\xb6\x87\xd2\x6b\xb8\x42\xee\x22\xa0\xf0\xd6\x6d\x93\x5f\x5d\x48\xc5\x40\xa5\x53\xb9\x3d\xed\x53\xc0\xd5\xa0\xff\xb9\x9e\xd7\xbe\x6b\x99\xd1\x9f\x23\x10\x32\xa8\xd2\x7b\xcc\xa8\x9e\x68\xb2\x70\x4a\xa3\x69\x63\x64\xec\xd0\x81\x8d\xea\xa1\x2e\x63\x50\xa5\xd4\xc5\x5c\x2d\x89\x77\xab\xf4\x2e\xb8\xb5\x83\x0f\x7a\x9d\xe4\xae\xd0\x43\xf3\x60\x91\x50\x74\xd0\x63\xab\x9e\xb5\xc1\xea\x49\xd3\x53\x55\xeb\x47\xa0\x25\xfb\x2e\x22\xcd\xe4\x11\xdb\x64\x55\xf9\xb9\xda\x82\x1a\xe8\x78\x00\x04\x9c\x7f\x8f\x49\xa4\xe9\xfd\x44\x12\x21\x0e\x8c\xa5\xbf\x8a\x67\x4f\xbe\x15\xb9\x32\xe0\x53\x8f\x02\x8d\x90\x25\x80\x78\xb0\x89\x1c\x7f\x74\xc2\x22\x69\x17\xbc\xd9\x71\x9b\xe1\x89\x9f\xad\x51\x6f\x69\xf5\xe1\x99\xe5", 218, { 0x3f, 0x10, 0x3c, 0xe1, 0x42, 0x47, 0xdd, 0x60, 0xf8, 0xc9, 0xaa, 0x84, 0xb6, 0x9e, 0x59, 0x03 }, { 0x0f, 0xf7, 0x5c, 0xc7, 0xa2, 0xb3, 0xd5, 0x03, 0x8d, 0x37, 0x74, 0x36, 0x8d, 0x66, 0x30, 0xe4 } },
{ "\x28\xc8\x75\xd5\x19\x17\xfb\x33\x9a\x5d\x70\x2a\x32\x7a\x3a\xad\xa7\x18\x98\xe0\x7d\x6e\x9d\x83\x75\xc0\xe3\x7c\x6c\x02\x15\xe3\x5c\xb7\x55\xf3\xdb\x30\x14\x1f\x3b\xe5\x46\xcc\xf1\x86\x3d\x04\x05\xd7\x2c\xa0\xe7\xb3\xee\x6f\x69\xda\x3d\xcb\x53\x01\xcc\x40\xe5\xee\x5d\x02\x2a\xd1\x89\xb6\x7e\xb0\x41\x08\x70\x0a\x28\x8d\x5f\x8a\x90\x4f\x50\xf1\xc0\x88\x82\x8c\xbe\x71\x6e\x46\x16\x60\xca\x81\x43\x6f\x2e\x60\x56\x0b\x32\xba\x20\x64\x84\xef\x67\x02\xca\x7f\xd2\x3a\xfb\xea\x11\x9c\x86\x10\x2c\x5c\x51\x2f\x99\x2a\xb0\xe0\xf2\xc5\x69\xf3\x37\xbc\x73\xd1\xe6\xaa\x6c\xfa\x8c\x49\xab\xec\xad\xfb\xf1\xaf\x7c\xb7\xb6\x9a\x57\x0f\xdc\x14\x19\xa3\x96\x3e\x1d\x49\x4d\x6c\xac\x22\xfd\x65\x78\xb2\xa0\x4a\xd8\x7f\xe0\xd9\x72\x03\xbe\x78\x3e\xf8\xf6\x80\xe0\xbf\xf7\x74\x51\x92\xba\x5f\x29\x22\xba\x79\x59\x77\xc3\xc2\xdc\x5c\x9f\x0b\x6a\x14\x8d\xae\x02\xc3\x0b\x85\x68\x17\x34\xcf\x2c", 219, { 0xd8, 0x09, 0x4e, 0xce, 0x9e, 0x25, 0x8e, 0x7d, 0xab, 0x35, 0x5c, 0xc0, 0xed, 0x23, 0x11, 0xc3 }, { 0x56, 0x85, 0x43, 0x4f, 0x2a, 0xb5, 0x10, 0x6f, 0xb9, 0x80, 0x15, 0x95, 0x00, 0x89, 0xdc, 0xb0 } },
{ "\xb8\x2e\x1e\x51\x99\x5c\x40\x50\xcf\x9f\x27\x8b\xeb\x69\x42\xbc\xd6\x9a\x1b\xae\x42\x06\x8c\xef\xb2\x53\xa7\xb0\xf8\xca\xf5\x66\xcc\xc5\xa7\x9b\x5e\xc1\x3c\x74\xec\xeb\x19\xfb\x9d\xe6\x25\x33\x90\x53\x98\xd5\xbf\xfb\x14\x14\x3c\xc0\xf9\xb8\x93\x43\x6a\x50\x36\xbd\x93\x3b\xa2\xe8\x50\xd6\x31\x00\x5c\x65\x7d\x99\xa2\x2f\x87\x99\x76\x36\x03\xe9\x8a\xa3\x24\x94\xf5\x0b\xce\x3d\x88\x95\xb5\x5d\xb4\xa1\xf6\x78\xae\x1b\x1f\x14\xa8\xc4\x44\x0e\xed\x4e\xdb\xc0\xab\xe7\xf7\x30\xb1\x4e\xf5\x9a\xf7\x6a\x32\x86\x6c\x37\x26\x7b\xfe\x0e\x5f\x02\x58\x25\xa6\x3a\x6e\xe9\xb4\xf1\xae\x71\xd7\xc1\xff\x52\xa1\x2f\x0d\x0b\x4d\x20\x38\x18\xbc\xe1\xc5\x7e\x8f\x38\x72\xf8\xe0\x28\xab\x4c\x03\x28\x9a\xc7\x82\x97\xd1\x61\x03\xfd\xe9\x03\x38\xdd\xdc\xf8\x86\xfa\x35\x89\x97\xf0\xdd\x4a\xc9\x8f\x58\x8a\xa2\x13\x6f\xc7\x52\x5c\x27\x3b\xf7\x6e\x97\x96\x58\x01\xe4\x48\x3f\x96\x62\x72\x3f\x39\xf8\x9a", 220, { 0x64, 0xea, 0x71, 0xeb, 0x6f, 0x96, 0xe6, 0x93, 0xdf, 0x17, 0x57, 0x0c, 0x3a, 0x59, 0xd9, 0x4d }, { 0x75, 0x69, 0x05, 0xcc, 0xf5, 0x17, 0x6f, 0x3e, 0x81, 0xbb, 0xd6, 0xd2, 0x10, 0x26, 0x6b, 0xfa } },
{ "\xa1\x68\x99\x53\x88\x81\x12\x3d\x8b\x03\x9c\xe0\x19\xcd\x8e\xd2\xbe\xef\x54\xd0\x7a\x05\xc4\x30\x20\x8b\xc2\x14\x9e\x50\xb7\x75\xeb\xd3\xa3\x92\xe7\x12\x81\x6e\x6a\xeb\x9f\xdf\xdc\x5a\x4e\xa0\x5e\x8c\x15\xfb\x5f\xb4\xec\x61\xed\x2e\x23\x15\xa7\x61\xdf\xf3\x21\xd3\x1c\xd1\x13\xf1\x3b\x56\x4c\xed\x6c\x3f\x87\xba\x92\x92\x38\x35\x31\xce\x33\xe6\xa2\xd3\x9f\xbc\x97\x25\xdc\xd5\x7a\x62\x79\x58\xda\xe8\x9c\x3c\xc2\x49\xfc\xb6\x76\x5f\x27\x1a\xe0\xef\xbe\x62\x01\x00\xf3\xba\x3c\x5f\x44\x59\x88\x50\xc5\xe3\xb0\xca\x15\x95\xab\x51\x79\x03\x60\x98\x84\x68\x16\xb5\x4a\xf2\x50\x50\x07\xdf\x8f\x0f\xa9\x22\x5d\xb6\xb1\x21\x6b\x21\x46\x32\xb6\x9b\xfb\xfb\xbb\xc0\xba\x07\x8c\xa3\x61\x8d\x50\x0c\x5a\x49\xc6\xf1\x42\x29\xeb\x88\xd3\xf2\x64\xbe\x60\x80\x26\x73\x0e\xd4\x93\xb1\xa9\xf9\xf5\xd9\x48\x44\xb7\xa7\x24\x67\x33\x62\xa8\x7d\xa3\xec\xdf\x95\x3d\xd5\xb2\x56\x66\xdb\x2b\x72\x60\x24\xe6", 221, { 0x52, 0x62, 0xcb, 0x8e, 0xea, 0xef, 0xba, 0x8a, 0xc9, 0x8c, 0x82, 0xe8, 0x78, 0x5a, 0x0c, 0x60 }, { 0x79, 0x7d, 0xcc, 0xd0, 0x10, 0x8a, 0xc9, 0x38, 0xf2, 0x27, 0xb3, 0xb0, 0x1d, 0x76, 0x69, 0x6e } },
{ "\x20\xb0\xec\xe9\x4f\x46\x8a\xc7\x77\xc4\xcb\x01\x56\x0a\xdb\xfa\x58\x80\x31\x52\xf5\xb8\xd0\x18\x1e\x29\x39\x0e\x27\xc6\x5f\xa2\xff\x2f\xdf\x28\x39\x69\x5d\xd9\xcf\x09\xb5\xbd\xb7\xc7\xa8\x0f\x6d\xe0\x24\x8e\x2f\xee\x67\xa9\x78\xb8\x87\x67\xec\xdb\xd2\x2d\x3c\xfe\x30\x80\x5d\x89\x6c\x61\x5c\xc0\x77\x74\xa7\x6c\xfc\xb6\xff\x33\xc7\xc8\x53\x83\xaf\x11\x8f\xec\xe4\x9a\xb5\x13\xda\x24\xe0\xc2\xfd\xe9\xf2\x77\xb6\xa4\x1f\x8e\x11\x75\xce\x6a\x81\x76\x15\x65\x80\x09\xfc\xfb\x32\xbb\x87\x20\xe4\x1d\x61\x14\xed\x11\xe9\xb3\x0c\x11\xe4\x19\xcd\xc9\xe3\x8c\x5c\x25\xf5\x6b\x02\x69\x47\x00\x4c\x5b\xf3\x43\x46\x7e\xd2\x3a\x5d\x6d\x5f\xbd\x5c\xbe\xa6\x01\x48\x13\x0d\x35\x0a\x33\x96\x8a\xba\xc7\x50\x5f\x08\x34\x72\xf3\x38\xa7\x7d\x94\xc5\xe5\xd3\x52\xb7\xe9\xb2\xa6\xe7\x5e\xe1\x52\xdf\x3d\x98\x45\xfd\x41\xf9\x83\x77\x63\xff\xa5\xcc\xa0\x90\x67\x5a\xd9\x05\x03\x97\xcc\x0b\xad\x3f\x31\x32\x31", 222, { 0x63, 0x4f, 0xb1, 0x4b, 0xbe, 0x8c, 0xc7, 0x1e, 0x78, 0x69, 0x77, 0x69, 0x5c, 0x58, 0xdf, 0xa2 }, { 0x84, 0x3e, 0xd6, 0xd4, 0xff, 0x60, 0xed, 0x1e, 0x57, 0xcc, 0x12, 0xc0, 0xa1, 0xb0, 0x11, 0x3c } },
{ "\x5e\xb1\xc1\x81\x9d\x5b\xce\x7f\xd8\x01\x9e\xc0\x10\xcf\x34\x34\xdd\x51\x6e\xb8\xdd\x74\x40\xdc\x04\x45\xca\xbd\x73\x06\xbd\x08\x5e\x56\x14\x7c\xac\x61\xe7\x84\x0f\xe5\xf2\x50\xa1\x22\x60\x28\xbd\x17\xeb\x40\x0e\x56\x69\x0a\xb2\x60\xbd\x17\xe2\x33\xec\xdf\xfd\xe4\xd1\xfa\x10\x9c\x99\x93\x8b\x15\x6f\xea\x0b\x1d\xc3\x84\x4e\x44\x71\x30\x8b\x7c\xc8\x2b\x1e\x44\x85\xb0\xe2\xfc\x70\x09\x92\xc7\xc2\xb4\x34\x8d\x05\x5a\x2d\xca\x8c\x0c\x0e\x89\x7a\xa6\x30\x4e\x68\xcb\xba\x41\xf5\x99\x8c\x03\x80\x89\x30\xaf\x42\x56\xfd\x23\x71\xd3\x34\x61\xda\xe6\x41\xf7\xce\xc0\x9a\xb3\x75\xf9\xff\x46\x1e\xb6\xd2\x62\x84\x61\xc3\x49\xc2\xa3\x21\xb7\x1f\x10\x7f\x82\x49\x6c\x08\x44\x63\xef\x35\xf4\x7e\xc5\x51\x02\x1d\xdf\x58\xd2\xfe\xb3\x98\xb2\xcf\x8f\xf6\x81\x47\x6a\xca\xcb\x70\x04\x4d\xe4\x2d\x9f\x7e\x12\x4c\x9d\x34\xb2\x1a\x8a\x81\x1a\x0a\x03\xf2\xba\xba\x7f\xc4\x21\x85\x30\x01\xd8\x26\xde\xc1\x1e\xe0", 223, { 0xd9, 0x75, 0xbe, 0x8a, 0xc8, 0x90, 0x22, 0xd2, 0x19, 0x92, 0x44, 0x82, 0x05, 0x92, 0xc4, 0x39 }, { 0xb0, 0xe8, 0x44, 0xae, 0xf6, 0xda, 0x62, 0xe2, 0xf5, 0x9d, 0xf5, 0x3e, 0xac, 0x1e, 0x56, 0x26 } },
{ "\x9a\x00\x59\x57\x56\x31\x17\x2c\x00\xf4\x4d\x4a\x52\x18\xf7\x40\x0c\xe0\x5c\xda\xe0\x98\x32\x80\x3b\x43\x15\x03\xdc\x5d\x05\x72\x06\xc1\xec\xd8\x21\x22\xed\xe2\x1b\xde\x13\x37\x80\x5f\xa6\xd4\x1c\x42\xde\x86\x84\x07\x0b\x85\xa3\xfb\x35\x92\xb0\xcf\x38\xc5\x1a\x89\xb7\x01\xb0\x3a\xa7\xee\xc5\x5d\xe3\x43\x4b\x1f\x9a\x6d\x15\x27\x46\x85\x2e\x09\xf7\x2e\x7d\x56\xb7\xf1\x02\x34\x77\x99\xda\xdc\x7f\x85\x65\xf9\xa5\x4b\xdc\x78\xfa\xb1\xfe\x3f\xfe\x1c\x05\x00\xc3\xd9\x05\x3d\x3e\xc6\xdd\x89\x8f\xbc\x52\x46\x86\x5f\xd4\xae\xa0\xf3\x5e\x9a\x18\x9a\x63\xf8\x2f\x55\x05\xcc\x2f\x91\x3e\xa9\x01\xfc\x6e\xb3\xcb\x95\x0f\x0a\xd0\x27\x53\x28\xa8\x4b\x71\xbf\x81\x89\x37\xaf\x3c\xda\xda\x28\x88\x92\xf4\x6a\xf0\x0f\x83\xcf\xd4\xed\x2a\xe5\x8f\xe6\x3d\xab\xea\x93\xbc\xdd\xa0\x09\x87\x01\xa5\x80\xfd\x24\xf8\xb3\xf2\x2a\x04\xdc\x9e\xfb\x75\xd1\x1e\x6c\xe8\x7d\x61\x0e\x8e\x73\x24\xf5\xbc\xa4\xaa\x04\x46\x90", 224, { 0x31, 0x93, 0x4d, 0x92, 0x4d, 0xe8, 0xbe, 0xf7, 0x26, 0xb6, 0x50, 0xc4, 0x37, 0x39, 0xb7, 0x3d }, { 0x47, 0xfd, 0xec, 0x8d, 0xec, 0x90, 0x08, 0xd1, 0xf3, 0x68, 0x41, 0x5f, 0x73, 0x5a, 0xbc, 0x2f } },
{ "\xfa\x4a\xd1\xb5\x8a\x8a\xc3\x36\xc8\x49\x5e\xb9\x56\x93\x01\xbb\xf2\x79\x12\xda\x65\x0f\xf6\x0a\x1b\xa4\x3a\xb1\x24\xca\x53\xac\x7b\xbe\xc9\x73\x17\xcf\x40\xfb\xc0\x87\xc6\xe8\x16\x75\x17\x60\x05\x02\x16\xa9\x90\x14\x28\x1a\xeb\x15\xea\x2e\x56\x78\x62\xf3\xac\x21\x6e\x23\xeb\xd5\x19\x31\xd4\xf4\xb1\xfc\xb7\xf2\x8a\x8c\xf7\x3a\x0b\xc7\x2d\x42\x55\x74\xa9\xe0\xe1\x23\x95\x16\xe1\x07\xf2\xe5\xc4\x4a\xfb\x89\x7e\x31\x61\x11\xb6\x62\xc4\x1d\x60\x7f\xad\x07\xb2\x48\xf9\x78\xd1\xdd\x4b\x34\x6b\xe4\x6c\xa3\xe9\x86\xfd\x8f\x41\xd6\x41\x13\xc0\x78\xf4\x3a\x4f\x8e\x92\x0c\x89\x01\x66\xd2\x93\xff\x86\xd6\x31\xaa\x99\xdc\x95\x36\xfa\x5d\xa8\xe4\x9d\x2b\x69\xd3\x1c\xf9\xca\x88\x7e\x1c\x95\xe9\xff\xf1\xb4\xb8\x9b\xf7\x2d\x3b\x26\x12\xe1\x02\x13\x28\xab\x1e\x48\xf5\x5d\xdc\xe2\x24\x8f\x84\xf3\x8c\xfd\x44\x5c\x56\x5f\xf6\x19\x33\xd0\xb0\x9d\x0d\x5a\x09\xf3\xc4\x5b\xbf\x42\xa7\x08\xd6\x16\xdc\x24\x95\xb0", 225, { 0x86, 0x3d, 0x44, 0x02, 0x59, 0xbe, 0x4a, 0x12, 0xf2, 0x33, 0xd7, 0xe0, 0x8a, 0xcf, 0xd8, 0x70 }, { 0x94, 0x47, 0xf0, 0x85, 0x1c, 0x62, 0x29, 0x66, 0x99, 0x5f, 0x5b, 0xcb, 0x70, 0xf6, 0x5f, 0x90 } },
{ "\xbc\x44\x67\xae\x61\x87\x82\xd1\x2d\x21\x9b\x11\x2a\x3f\x55\x4c\x13\x42\xda\x14\x9f\x31\xa2\x1f\x95\xb0\x56\xb6\x28\xc8\x60\x63\xf5\x9d\x3a\xf0\xb5\x80\x2e\xfd\xcf\x8b\xc0\xd6\xb0\x93\xdd\x69\x71\x35\x2c\x4e\x99\x25\x45\xfe\x5a\xd9\x29\x00\xb1\x13\x96\x6b\x9a\xde\x24\x9a\xa7\x25\xb6\x5f\xbb\x96\xca\x59\x2b\x4b\x4e\xd2\x04\x08\x91\x56\xf3\x21\x90\x66\xf8\xb7\x08\x9a\x2c\x1d\x73\x8a\x0c\xfb\xc8\xb1\xc6\x04\x23\x31\xc2\xf6\x93\x9c\x82\xb2\xc8\x39\x90\x8f\xce\xa5\x46\x0e\xe3\x3e\xd0\x1b\xf9\xc6\xa7\x80\x89\xc7\x0c\xce\xba\x12\x74\x33\x48\x35\x7f\x28\xdc\x42\xf5\xb7\x8a\xe5\x5b\x26\xd1\x2b\x6c\x66\x4a\xcf\xca\xc3\xf2\x57\xcb\xd6\xa3\x88\xac\x58\xcd\x34\x4e\xc9\xcf\x8b\xab\x09\xad\xee\xc5\xc1\x32\x25\xec\xf4\x3a\x28\xcb\x20\xe2\xd3\xc2\x41\x6d\x96\xb6\x44\x0b\xd3\xf4\xb7\xe7\xff\x8f\xef\x94\x2d\x8f\xd1\x2a\x5d\x72\xc6\x4f\xe6\x06\x4f\xda\x1d\xa1\x34\x49\x34\x52\x20\xea\x16\x49\x98\x5c\xd5\xba\xf5", 226, { 0x75, 0xe5, 0x14, 0x6d, 0x22, 0xdb, 0xab, 0x6d, 0xe0, 0x93, 0x77, 0x05, 0x8f, 0xdc, 0xb2, 0xdc }, { 0x0f, 0xcc, 0x76, 0xd5, 0x7b, 0xba, 0xf8, 0x4e, 0x25, 0x83, 0xd1, 0x04, 0x2d, 0x52, 0x8b, 0x9d } },
{ "\x47\x77\xa5\x59\xe6\xbd\x9d\xf9\xe5\x28\xf1\x23\x7f\x07\x70\xde\x76\x14\x34\x77\x94\xbf\xd1\xa4\x0a\x9b\x30\x20\xaa\x96\xd6\x58\x6d\x2a\x3f\x80\xbe\x30\x64\xec\x65\xbf\xc7\x14\xfe\x64\xa2\x27\x18\xf3\x26\x76\x36\x36\x14\x3e\xc0\xea\xfb\x28\x83\x08\xa3\xb2\xe3\x01\x98\x84\x58\xdf\x64\xae\xd7\x04\xe1\xf7\x47\xa6\x76\x5e\xbb\xe9\x39\x11\x8b\xf1\xeb\x36\x99\x02\xfe\xef\xc8\x88\xae\xe1\x57\xcb\x73\x2f\xf0\xe5\x13\xe1\xe1\xe4\x1e\xc9\x11\xb1\x6f\x38\x7e\x3b\xf4\xed\x43\x86\x80\x4d\xfb\x08\x2c\x86\x7f\x59\x0d\x04\xc2\xeb\x03\xef\xc5\x28\x6d\x8b\x05\xb3\x53\xc5\x32\x55\x77\x42\x08\xce\x6a\xf8\xba\xd2\x3c\x31\xb1\x4d\x61\xe7\x85\x04\x7e\x98\xbc\x3e\x67\x54\xe5\x99\x27\x02\x63\x92\x49\xb6\x56\x1f\x5a\xe8\x25\xb1\x66\x24\x4c\xb3\x8d\x46\x73\x2f\xbb\xcd\x23\x8f\xb3\x17\x09\x12\x62\x84\x05\xa6\x14\xea\x4c\xed\x35\x6c\x2c\xb0\xef\x5a\xed\xab\xe0\x06\xef\xf3\x3c\x72\xb3\x30\x54\x76\x58\xc8\xec\xb7\x71\x75\xdb", 227, { 0x3b, 0x55, 0xf3, 0x29, 0x87, 0x72, 0xef, 0xe8, 0xf6, 0x0b, 0x76, 0x20, 0x0b, 0xe4, 0xf3, 0x14 }, { 0x20, 0x0a, 0x0e, 0x02, 0x20, 0xfa, 0x04, 0xfa, 0x91, 0xcb, 0x4b, 0x96, 0x29, 0x90, 0xd2, 0x74 } },
{ "\x4f\xcd\x15\x56\xfa\xe3\xd8\x67\x32\xd9\xcd\x32\x6c\xde\x4a\xde\xa5\xcf\xd9\x08\xbc\x11\x29\xf1\x17\x5d\x75\x1b\xf2\xa6\xa0\xb9\x82\x0d\x6c\x46\x07\x3c\x22\xea\x5f\x82\x42\xe9\x05\x35\xed\xbc\xe7\xf5\x73\x43\x58\x03\xe5\x27\x59\xe9\x7c\x27\xd6\x1e\xa9\x46\x3a\x69\x98\x8e\xb4\x4b\x6e\x96\x64\xad\x7e\xe7\xfc\x80\xef\xee\xec\x09\x92\x0d\xd5\x05\x8c\x10\x29\x9b\xe3\xd2\xe4\xbd\xdf\x5d\xe9\xc5\x09\x25\x57\x89\x2b\x41\x1f\x90\xa5\x83\x24\x5a\x69\xcd\xbc\xc8\xae\x13\xa7\x99\x0c\xca\x60\x58\xd6\x1e\x13\xd2\xf9\xb2\x2d\x52\x58\x54\xd0\x47\x19\x4d\x10\x06\x88\x7f\x2c\xdb\x9a\xfe\x49\xd3\xcf\xa6\xfa\x48\x03\x05\xca\x1f\xdd\xe3\x76\xdf\x91\x3d\x7a\x2a\x4a\x57\x6a\xc6\xe5\x07\x3e\x22\x72\xa1\x76\xb1\xee\x26\x94\xa8\x76\xec\x99\x1a\xe9\xd2\x6c\x95\xf0\x90\x43\x4e\xcd\x02\xf7\x7b\xf7\xf1\xd5\xb4\x38\x17\x30\x31\xf9\xdc\x0e\x89\x8d\xb9\xf8\x59\xf5\x5a\x53\xf0\x61\x2b\x2a\xb3\x38\x69\x31\x78\xf5\x79\xd1\xcd\xb8\xa8", 228, { 0xb4, 0x12, 0x5d, 0x0b, 0xcc, 0x36, 0x53, 0xae, 0x80, 0x46, 0x58, 0xd9, 0x3d, 0xdf, 0xf3, 0xaa }, { 0x0b, 0x41, 0x5f, 0x89, 0x63, 0x0c, 0x42, 0xb7, 0xf6, 0x0f, 0x9d, 0x02, 0x93, 0xfa, 0x3a, 0x45 } },
{ "\xb9\x15\x8e\xb1\x1d\x61\x2d\x4d\x64\x2e\x67\x91\x11\x9a\x8b\x40\xab\xbb\xc2\x47\x51\x76\x82\x75\x74\x36\x16\x90\x37\x42\x41\x13\x7a\x29\x0a\xb4\x08\x6c\x21\xbc\x97\xab\x7e\x0b\xd8\x65\x30\xae\x70\x57\xb7\xee\xa2\xc9\x7d\x97\x44\x83\x7a\x52\x85\x1e\xe7\x44\xf3\x1d\xb3\x79\xd8\xc3\x51\xc6\x05\x30\x68\xb5\x10\x44\x8e\xa5\x0e\x91\x9b\xc2\x50\x67\x3e\xf7\xa7\xd4\x1d\x00\xa1\xf7\x43\xfe\xcb\xd7\x1f\xd7\xb6\x9b\x59\x50\xb3\x3a\xe4\x75\x4a\x9f\x6e\xe8\x3c\xb9\xb5\xd1\x82\x55\x54\xce\x53\x8f\x78\xb7\x79\xa8\x32\x99\x5c\x45\xaf\x76\x8b\xc8\x15\x7f\xf4\xaa\x34\x0b\x44\x38\xc4\xf0\xdb\x2a\xfe\xd1\x3b\xe6\xf3\xe9\x51\xe0\x08\x76\x5d\xf7\x5c\x9f\x76\xca\xaf\xf9\xdf\x77\xfb\x4d\x12\x64\x62\xb5\x8b\x20\x2c\x50\xcb\xb5\x14\x8e\x5e\xcc\xed\xcb\x6d\x4d\x0e\x11\x4f\x1e\xfc\x88\x6a\x18\x9e\x33\x15\x5c\x71\xd6\xef\x9e\x45\xaa\xb7\xdf\x7f\x21\xf2\xdb\x53\x9d\x8d\x03\xb9\x41\x46\xd6\x95\x56\x25\xf2\x53\x23\x47\x06\xda\x23\xea", 229, { 0x6a, 0x16, 0x68, 0x2f, 0xa4, 0xa5, 0xfb, 0x73, 0xff, 0x85, 0xdc, 0xfb, 0x93, 0x34, 0x11, 0xae }, { 0xbc, 0x1a, 0xcf, 0xf0, 0x9a, 0x05, 0x99, 0xe2, 0xea, 0x27, 0xad, 0x50, 0x08, 0x7a, 0xaf, 0xaa } },
{ "\x79\x5c\x4d\x67\xd6\x5c\x20\xa0\x39\x71\xd8\x0e\xf3\x0c\xc3\x5b\x1c\x4b\xea\x6e\x8e\xc3\x90\x1d\x2b\xa7\xcf\xa3\x36\x9e\x75\xf7\x45\xda\xd5\xfa\x9c\xe0\xcc\x6b\x82\x99\x65\x50\xb0\x5a\xa5\xa5\x01\x02\x4d\x80\xa3\xae\xbc\xec\xc1\x0b\x75\x9c\x8b\xa6\xa2\xe1\x01\x1a\xa9\x9e\x30\x49\xad\x20\x2f\xab\x91\x4c\xa6\x71\xc4\xfc\x76\x72\x40\x7f\xe9\x5b\x4f\xb2\xf1\xf9\x46\x95\xc5\xe3\xbc\x09\x18\xe1\x14\x7d\x08\xe5\xc3\x67\xe2\xbe\x9f\x91\xea\x00\x46\xe3\x34\x34\x50\x68\x79\x43\x3e\x3a\x39\x7b\x62\x1d\x57\x0e\x59\xe0\x2a\x3c\xe5\x71\x0d\x22\x66\x76\x37\x4b\x35\xf8\x2d\x96\xa5\xc8\x85\x0c\xa9\xce\xd9\x31\xcf\x7f\x4f\x92\x2c\xc7\x5d\x5d\x35\xab\xdc\x46\x11\xa3\xd8\xc1\xc6\xbb\x74\xd2\x64\x04\xfd\x6d\xc4\x3f\x11\xd8\x52\xf9\xc6\x82\x80\x24\x1d\x6a\xd3\x86\x95\xd0\x24\xe1\xe7\xc0\x25\xf0\xea\x36\x4c\x9b\x67\x33\xe4\xff\x29\x50\xc4\x6b\x2a\x7c\xc7\x96\x7c\x7c\x82\x2a\xa0\xc8\x42\x5b\xc2\x6a\x22\x9f\x34\x25\xad\x9b\xd7\x58", 230, { 0x8f, 0xa7, 0x94, 0x44, 0x83, 0x2d, 0xb7, 0x3c, 0x9c, 0xbc, 0x10, 0x1e, 0xbb, 0xa2, 0x5b, 0xfd }, { 0x43, 0xbc, 0x9b, 0x29, 0x10, 0x86, 0xee, 0x9c, 0x54, 0xa8, 0x61, 0x53, 0x6b, 0x22, 0xef, 0x7a } },
{ "\x4f\x3b\x87\xa4\xab\x9e\xf2\xd7\x38\x91\x3e\x18\x35\x82\xd8\x33\xb3\x2c\x8a\xf8\xfb\x2b\x89\x4c\xf3\x93\xbf\xf2\xa6\xc3\x4a\x46\xfe\x15\xf9\x4f\x0a\x43\xfd\xb6\x1a\x9d\x02\xc4\x0b\x20\xd1\x07\x07\x9f\xad\xd7\x30\x6d\x66\x16\xc4\x41\x94\xb9\x0e\x81\x39\x8b\x86\xf0\x32\x3f\x03\xd5\x1d\x71\xec\x80\x45\x4b\x4e\x08\x15\xa6\xaf\xea\xb4\x55\x73\x52\xdd\xb9\x17\x8f\x12\x5b\x97\xfc\xb4\xd9\x3f\x7a\x60\xed\x8a\x6b\x11\xa8\xed\x83\xbf\x85\x5d\xf5\xea\x49\x58\x1b\x82\x0d\xb2\xcd\xe4\x8d\x4e\x29\x4c\xdc\x6b\xfb\x95\x04\x48\x85\xb7\xf1\xd2\x91\xb4\x41\x8c\x1e\x45\x84\x5f\x09\xff\x76\xbf\xea\x82\x2d\xf1\xc2\x79\xfd\x84\x7c\x75\x7b\x19\x37\x37\x48\x66\xca\x13\x28\x8c\xfe\xba\x82\xbd\x57\x99\x74\xd0\xa6\x0b\xdd\xfd\x0d\x8d\x7d\x36\x8f\xb9\x2f\x91\xad\xc3\x4e\xab\xa0\x2b\x9a\x78\x1b\x76\x37\x87\x4a\x1d\x20\x33\x1b\x9f\x5e\x32\x88\x3f\x99\x92\xc5\x9a\x47\x8b\x74\x25\xdb\xb3\xad\xfc\x1c\xd4\xc6\x9f\xba\xb5\xfa\xf5\xb1\x48\x79\x7f", 231, { 0xff, 0x87, 0xd4, 0x1c, 0x80, 0x6c, 0x11, 0x6b, 0x82, 0xd7, 0x67, 0x22, 0x5b, 0xab, 0xb4, 0xf9 }, { 0x90, 0x24, 0x86, 0x1a, 0x7b, 0xc6, 0x64, 0x7b, 0x7f, 0x90, 0x00, 0xb9, 0x31, 0x22, 0xc3, 0xec } },
{ "\xe2\x86\xf1\x0c\xe8\x59\x56\xb0\x9e\x18\x1a\x54\xff\x07\x8b\xfb\x7b\xcf\xcb\xa0\xbd\x38\x36\x25\x8e\xfd\x5b\x1d\x30\xe6\x28\xa4\xf1\x54\x25\x5c\x77\x9b\xb1\xc8\xae\xac\xa1\x06\x05\x45\xd8\x22\xfc\x2a\x30\x92\xe4\x30\xbf\x51\x01\x95\xc0\x5e\xf8\x5f\xf8\xaf\x17\x53\xe5\xc9\x67\x76\x39\x6d\x8f\x80\x7a\xd2\x81\x44\xc1\xd5\x3a\xef\x08\xf6\x17\xcc\x8f\x63\xe5\x61\x3f\xa1\x0f\x63\x21\xc4\xd3\x53\x46\x71\x62\xfb\xc7\xef\x53\x79\xdb\x4f\x82\x88\x61\x96\x2f\xba\xee\x30\x4d\xf9\xb9\x94\xd1\xb3\x9a\x88\x74\x37\xd6\x48\xe1\xfa\x24\xe4\x94\xd3\xe5\x7e\xb8\xac\x3b\x7a\x16\x8b\x7c\x8f\xf0\x9d\x21\xd8\xf6\x63\x69\xfe\x16\x4b\xbe\xbc\x4f\x58\x71\x7a\xe8\x2c\x5d\x34\x27\xa9\x1a\x3c\x9d\xf0\x13\x48\xa1\x39\x78\xa1\xf4\x09\x81\xc1\x7c\xb6\xa1\x78\xae\xc8\x68\x72\x60\xe9\x71\xfa\x12\x99\x3c\x73\xec\x8b\x21\x25\x4a\x88\x16\x53\xb7\x7a\xee\x8b\xbc\x78\x74\xbe\x05\x81\x8e\xff\xcd\xae\x9c\x14\x08\xfc\x44\x79\xb5\x7b\xe2\xe5\x64\x58\x43\x49", 232, { 0x64, 0x4f, 0x80, 0xd1, 0xf0, 0x13, 0x38, 0x1b, 0xaf, 0xbe, 0x28, 0xd7, 0x20, 0x28, 0xe2, 0x39 }, { 0x47, 0x69, 0xf2, 0xf6, 0xc7, 0xb0, 0xfe, 0x40, 0x8b, 0x02, 0x5e, 0x20, 0x94, 0x04, 0x20, 0xe0 } },
{ "\x4a\x9a\xd5\x32\x08\x49\x18\xf2\x24\x2b\x36\xd9\x58\x6e\x0a\x5d\xce\xc7\xb0\x4d\x35\xe7\x85\xfd\x24\x26\xfc\x81\x72\x86\xd6\x8a\x0d\x45\xa2\x9f\x7a\x87\xc4\xee\x5c\xec\xfe\x86\x2c\xc0\xb6\x01\xb0\xd1\x3e\x30\x97\x91\x85\x35\x9d\x7a\x15\x85\xef\xdc\x9e\xbd\x9f\x31\x40\xf0\xa2\x58\x38\xd7\x01\xae\xe6\x97\x9b\x69\x65\x6d\xa4\x38\x65\x72\x25\xab\xe9\xd7\x5b\xd3\x7d\x0a\xc6\xfb\x2f\x8c\x27\x5d\x12\x9b\xbd\xa3\x94\x0c\xf9\xbc\xda\x90\xd7\x82\x16\xec\xad\xac\x8f\x17\xfa\xaa\x24\x89\xd3\xcb\x12\x27\xa3\x25\xda\x56\x28\x49\x67\xbe\x09\xbf\xc4\x1d\x7b\x00\xae\x4f\xe0\x29\xf4\x05\xb1\x83\x79\xa6\xda\x7f\x71\x3e\xf9\x93\xdd\x63\x0b\xce\x92\xae\x5d\xd1\x4f\x45\xd1\xf2\xc2\xd8\x0c\x5d\x91\xec\x0d\x5a\x24\x02\x4c\x83\xe9\x34\xc5\x39\x24\xec\x78\x14\x6b\x5f\x88\x1f\xfd\x51\x10\x0e\x76\x1f\x55\x3a\x00\x01\x3c\xb7\x79\xa5\xc6\x09\x82\x0c\x77\x11\xf9\x65\x58\xad\x8d\x80\xa1\xfd\xcd\x4a\x95\x55\x84\xd2\x0c\x0c\xcf\x55\x42\xb9\x8a\x01\xdb", 233, { 0xc5, 0x1c, 0x65, 0x09, 0x8b, 0xc0, 0xc4, 0x19, 0xa7, 0x51, 0xaf, 0x94, 0x9a, 0x8a, 0x36, 0xa5 }, { 0x4c, 0xe9, 0x71, 0x07, 0x7d, 0x9f, 0x3b, 0xb2, 0xfa, 0x07, 0x0e, 0xa1, 0xe6, 0x63, 0x98, 0xf9 } },
{ "\x17\x44\xdd\xc8\x2b\xb4\xa6\x9f\xc2\xed\xe0\x9f\x2a\x5f\xf9\x60\x5d\xcf\x0d\x29\xe0\xc6\x8e\xa8\xc3\xd2\xa6\xde\x19\x0c\x0f\xa2\x2d\xdc\xf2\xc8\x13\x7d\x74\x85\x26\xba\xaf\x45\x4b\xac\x12\x23\x89\xa7\x1b\x4d\xc8\x26\xe0\x9b\x69\x82\x99\x76\xe9\x08\xfa\xf4\xdc\xf9\xd8\x3b\x30\x30\x0f\x4a\x75\x4a\x0c\x5d\x4c\x51\xd5\xcb\x7a\x23\x1c\x5c\x22\x74\xb5\x08\xae\xf6\xf7\xf9\x70\xb6\xa9\xb7\xe3\xda\x2f\x04\xf5\x8c\x77\x09\x00\x57\x42\x5d\x63\x4a\x8d\x33\x50\x2b\xe7\x7c\xd0\x64\x64\xe2\x38\x1d\x1c\x5a\x98\xb1\xd0\x42\x3f\xc2\x3e\x0a\x65\x47\x8b\x2e\xb6\x97\x7e\x65\x6f\x9e\x2a\x4c\x14\x2a\x51\xe0\xcf\xfd\x4c\xab\x1f\x25\xb3\xc1\x53\xf9\x51\x23\x20\x4d\x3c\x0d\xa6\x58\xd6\x23\x64\xdb\xfe\x48\xbe\xee\x6f\x28\xf8\xfb\xd3\x69\xff\x76\x48\x91\xea\xd7\xd8\xa1\x57\x01\xb4\xe5\xa2\xd7\x5f\x3b\xab\x6a\x01\xe2\xfa\xbe\xe5\x0b\x5f\x98\xba\x32\x99\xea\xc1\x24\x63\x8e\x94\x48\xac\x0d\xba\x49\x12\xeb\xac\xda\x6e\xfc\x30\x89\xfa\x70\x67\x40\xb3\x2d", 234, { 0xba, 0x9f, 0xd2, 0x3c, 0xbf, 0xa2, 0xf5, 0xd0, 0x5e, 0xa3, 0x7d, 0x0f, 0x66, 0xb8, 0x50, 0xae }, { 0x79, 0xd1, 0x1b, 0xba, 0x26, 0x2b, 0xcf, 0xc7, 0xe1, 0x8b, 0x4f, 0xde, 0xf4, 0x14, 0x72, 0x0a } },
{ "\x59\x40\x46\x08\x47\xb8\xb4\x81\x57\x7f\x9e\x93\xf4\xe8\xc2\x95\xa8\xf3\x36\x88\x14\x3d\x1d\xbb\xa9\x79\x9a\x61\x36\x45\x02\x0d\xaa\x70\x63\x4e\x36\x9c\x69\x16\xb1\x22\x01\x35\x0d\xfd\xb1\xfc\x19\x9a\x06\xd4\xd5\xd0\x1a\xef\x49\xdf\xcf\xa3\x43\xed\x8b\x2f\x47\x18\x6f\xd4\x5f\xc5\xa9\xe4\xe8\x52\xc2\x63\x6f\xa0\x00\x3e\xb0\xe9\x53\x86\x49\x8d\x50\xfb\xb1\x1d\x63\x70\x66\x44\x7d\xf8\x98\x9a\xca\x36\xfc\x45\xda\x1c\x62\xdd\x35\xbf\xe0\xa5\xba\xad\x07\x52\xb9\xc4\xe4\x98\x1c\x7d\xc0\xb8\x70\xa8\xbd\x73\x2e\x33\x0a\x6f\x76\x13\x13\x41\x40\xbe\xb9\x61\xc9\xf8\xd1\x6e\x53\xb2\xe8\xa1\xfe\xf4\x06\x0a\xf3\x80\x6a\x62\x8b\xf3\x1e\x14\xe6\x61\x55\xa9\x97\x81\x33\x13\x94\xe3\x03\x43\x5a\x80\x81\xdd\xf9\x7c\x79\x6d\x26\xdf\x32\xa1\xc9\x3b\xd8\x49\x9f\x39\xc9\x41\x03\x4b\x04\xa7\x04\xd5\xca\xd2\xec\x1f\xce\xf0\xcf\xff\x74\xb2\x7d\x48\x11\x3d\xd8\x01\x54\x52\x5d\x45\xdf\x6b\x34\xe7\xd5\x0e\x2f\xf0\x82\xbf\x16\x66\xc9\x0a\x95\x0c\x00\xef\x75", 235, { 0xf3, 0x6e, 0x77, 0xcf, 0xfc, 0xbd, 0x78, 0xd4, 0x92, 0x3e, 0x91, 0x24, 0x89, 0xb6, 0x85, 0xa0 }, { 0xe7, 0xf0, 0xaf, 0x5e, 0xc5, 0x65, 0x23, 0xa7, 0x2f, 0x54, 0xe9, 0x42, 0xfe, 0xd9, 0xdc, 0xf8 } },
{ "\x1a\x19\xb2\xf6\x0e\x67\xf3\x77\xde\xea\xaf\xff\x6d\x24\xd2\xf8\x5d\xf1\x17\x49\x11\x39\x8a\x33\x5c\x60\xbf\xfe\xc4\xf7\x0a\x75\xae\x00\xf3\x0b\xf8\x39\xf2\x4f\xd2\x11\x1b\xb5\xb0\x90\xca\xf6\x58\x90\x42\x2b\x7a\x73\xdd\x34\x22\x1c\x6b\x1a\xc5\xa3\x53\x27\x45\x46\x2d\x5a\x54\xde\xca\x8f\x7a\xb5\xcf\x14\xee\xeb\xab\xaf\x33\x6c\xfb\x28\x02\x27\x2c\x1f\x67\x06\x37\xce\x60\x74\x44\x2e\xfb\xcb\xc4\xbb\x7d\xcb\x75\xed\x9d\xe7\x38\xc9\x98\xcc\x57\x49\xca\x5d\xbb\xbf\xf8\x5b\xae\xab\xec\x5f\x3b\x30\x5e\x9f\x24\x15\x01\x8c\x5b\x23\x8e\x1c\x50\x11\xcb\xbc\x30\x8b\x61\xf7\xd0\xcd\x8a\x3c\xe2\xf4\x78\x9c\x9b\xd7\x9e\xad\x28\xb8\x43\x31\x2e\xcd\xf9\x16\x3a\xac\x0e\xad\xae\x0a\x7e\x03\x55\x82\x64\x36\x71\x25\xfd\x63\xa6\x6d\xf3\x26\xd0\xff\xd7\xe8\x7e\xec\x53\x6f\xa8\xad\xe1\xdb\xa7\xfa\x07\xaa\x3a\x3e\x6f\x61\xe9\x22\xf9\xa5\xeb\x53\xb9\x22\x33\xba\xb7\x39\xd6\x98\xc4\x80\xe2\xc1\xaa\x04\x15\x33\x1c\x39\xf2\xe7\x25\xfa\x58\x10\x9c\x9f\x63\x3b", 236, { 0x78, 0x91, 0xf6, 0x46, 0x46, 0xf2, 0x05, 0x0d, 0xe6, 0x1d, 0x58, 0x7a, 0x05, 0xf6, 0xe2, 0x0e }, { 0x67, 0x0c, 0x51, 0xe1, 0x96, 0xe7, 0x0e, 0x46, 0x3a, 0x9d, 0x7e, 0xc5, 0x4c, 0xd6, 0x45, 0x91 } },
{ "\x1d\xc1\x48\xff\xe9\x39\xa1\xba\x63\x99\x4d\x22\x4e\x16\x3e\x9e\x2c\x52\x9e\x99\x00\xc1\x91\xb9\x70\x61\x51\xe6\x6a\xf1\x18\xed\xc1\x47\x31\x3c\xc4\xb2\x44\xde\x44\xef\xc4\xf6\x59\x72\x6d\x10\x8d\x20\xff\xa3\xc3\xf9\x6b\xe5\x35\xb2\xd0\x51\x77\xd6\x63\x68\xb1\x80\x0e\xd2\x91\x1b\x76\x02\x03\x8f\xbf\x5a\x40\x95\x3e\x53\x33\xfe\x15\xc3\xd4\x8c\x21\x2e\x1a\x99\x1e\xe9\x1d\xac\xc6\x4a\xf4\x81\x22\xb9\x23\x2b\xc5\x95\x47\x14\x5c\x81\xda\x1a\xf0\x9f\x0f\x10\xd8\x2d\x40\x4a\xb9\xf8\x46\x11\xb7\x19\xc4\x53\x10\x14\xf6\x25\x42\xf5\xd9\x55\x4b\xd2\x1c\xf3\x2b\xd6\xe6\xa0\xc4\xd4\x2e\xbd\x93\x77\x03\x27\x8e\x47\x73\x6c\x65\x8c\xea\xe7\xb9\x18\xdc\x63\x31\x3b\x2a\xe3\x6f\x82\xd9\xaa\x67\xf4\x47\x24\x52\x72\x4b\x1d\x91\xfb\xcd\x02\x27\x74\x17\x39\xa7\x8d\x91\xd6\x61\x38\x1d\xca\x0c\x96\xf1\xd1\x12\x18\x10\x27\x5d\xd8\x51\x65\x5d\xcd\xe8\xf9\xbf\xae\xe0\xfd\xa0\x17\xf5\xdb\xb1\x5c\xec\xcc\xc3\xbf\x66\x43\xb1\x0e\x8e\x3d\xe1\xac\x01\x3e\x17\xcd\xc8", 237, { 0x57, 0xa3, 0x10, 0xb7, 0x8e, 0x94, 0x82, 0xf9, 0x24, 0x93, 0x06, 0xad, 0xd1, 0x10, 0x43, 0x0b }, { 0x63, 0x53, 0x60, 0x23, 0x39, 0x09, 0xb9, 0xf6, 0x5c, 0xbe, 0x86, 0x08, 0x79, 0xa6, 0x20, 0x60 } },
{ "\x92\x52\x87\x34\x72\xe3\x1d\x5c\x57\x91\x7d\xfe\x8c\x4f\x09\xa7\x58\xd9\x47\x06\xdb\x9f\x14\xc8\xb6\x90\x40\x9e\x13\x10\x0e\xba\x76\xde\x79\x26\xfc\x89\x3d\xd0\xf1\xbd\x19\xf1\xc3\xb1\x0b\x6f\xb6\x76\x5f\x62\xeb\x6a\xea\x66\x9c\x16\x1f\x43\x0d\x27\x21\xf3\xa6\xd6\x8b\xba\x02\xd3\x5c\x86\x23\xf4\x99\xcb\xd8\x69\x25\xf7\xf5\x13\x0a\xfe\xae\x51\x6d\xfb\xf0\x79\xd0\x06\x28\x96\xff\x67\xdf\x0f\x7b\xcf\x2a\x12\xaf\x8d\x4e\xff\x46\xfd\xc4\xfe\x94\xeb\x85\xcb\x6b\xc8\xe7\xa4\x47\xd1\x4b\x68\x03\xbb\xfd\x67\xdd\x24\x67\x15\x72\x65\x73\x5b\x19\x52\x5e\xa4\xd3\x89\xe0\x9f\xe9\xfe\x3a\x77\x0c\x04\xef\x3c\xb7\x9a\xe7\x96\x28\x40\xc9\x31\x72\xd8\xc5\x0a\x6a\xb4\x32\x0e\x5f\xfd\xa9\x27\x20\xfa\xbf\x38\x10\xc9\xbd\x7d\xa4\x23\x56\xb6\x03\x86\xad\x6d\x19\x97\x92\xd2\x72\xbb\x54\x09\x3c\x33\x45\x05\xb9\x80\x4d\xe1\xfd\xd5\x8e\xb8\x06\x83\x9f\x58\xd7\x3d\x1f\x7c\xc3\x92\x4b\x0c\xe4\x91\xac\xbb\x65\xc3\x6f\x53\xb6\x66\x3a\xa4\xf3\x4a\x19\xd3\x7a\x3c\xd2\x3f", 238, { 0x3e, 0x02, 0x3f, 0x4d, 0xf0, 0x60, 0x97, 0x09, 0x3d, 0xe8, 0xf7, 0x45, 0xe5, 0xf3, 0x23, 0xf3 }, { 0xe2, 0xd8, 0x04, 0x3f, 0x56, 0x4d, 0xc6, 0x18, 0x3a, 0xf5, 0x65, 0x2b, 0x59, 0xd3, 0x80, 0x9c } },
{ "\xeb\x47\xbb\x17\x82\xfd\xc4\xb5\x36\x20\xd6\x3e\xe0\xae\x80\x76\x1d\xbc\x8d\x51\x8d\x01\xd7\xaf\x5a\xcd\x7c\x6e\x7e\x11\x53\xa5\x3c\x21\xe7\x74\x22\x9d\x78\xc4\x24\xba\x78\x77\x01\x4b\x36\x25\x01\x30\x16\x3c\x9d\xc9\x8c\xac\xdf\xd8\xc0\x22\x8c\xe0\xd8\xb3\xf4\x2e\x5b\x03\x95\x88\x0c\x76\xbe\x8c\x2c\xa5\x53\x94\x1c\xbd\x3d\x3e\xb2\xec\x7a\xc5\x41\x51\x1c\x80\x96\x81\x31\xb5\x57\xb2\x44\xd7\xe5\xde\x37\xdf\x71\xd8\x4b\xad\x55\x2e\xf5\x24\xd3\xbb\xfc\xe4\x34\xb7\x6c\x89\x58\x1b\x34\xf9\xda\x0e\x76\x40\xb6\x71\x20\x32\x01\x5c\x8a\x4a\x89\x6a\xbc\xff\x35\x68\xb6\xa5\x4f\xac\x52\x2b\xb4\x50\x24\x58\xf6\xe5\x7e\x51\xdc\x92\x1f\xe9\x7a\x52\x6b\x74\x5d\x20\xf0\x30\x5e\x92\x18\x98\x1a\x68\xb7\xeb\x69\x40\x63\xf4\xf6\xbc\x9b\x49\xe3\xe0\x77\x26\x7c\xe5\x6a\xfa\x03\x0b\xbf\x42\x2c\xc8\xd6\x57\x37\xae\xed\xaa\x46\x30\xd2\x81\xad\x27\x21\x97\xb8\x79\xb1\xba\xa8\xf3\xaf\xc2\x23\xd3\x61\xc5\xce\xbf\x6c\x64\xe1\x26\x9a\x2d\xaa\x6b\xe0\x65\x15\x5e\xc4\x7c\x49", 239, { 0x54, 0xa5, 0xd5, 0xe1, 0xe9, 0x3e, 0x60, 0xf7, 0x2b, 0x9c, 0x81, 0x4c, 0x00, 0x45, 0x5c, 0x55 }, { 0x26, 0x38, 0x9c, 0x4a, 0xf8, 0x53, 0x2a, 0xa1, 0xa4, 0x97, 0x10, 0x1a, 0x4b, 0xff, 0xc1, 0x2c } },
{ "\x84\x28\x1f\xdc\x0e\xcd\xf0\x6a\x56\x89\x34\x8e\x64\x3a\x40\xe9\x15\x12\xe6\x43\xd2\x58\x61\x39\xa5\x11\x85\x91\xcc\x02\xee\x37\x54\x9e\x87\x72\xd3\x96\x00\x4d\x81\xee\x94\x5a\xb8\x62\xa6\x9d\xd0\x70\x16\x85\x66\x86\x18\x85\x68\x8b\x50\x10\x98\xfc\xe6\xa5\xda\x80\x25\xc8\x97\x07\x61\x37\x13\x4f\xce\xcc\xcc\xe8\x19\xe2\xc0\xd6\xe7\x4b\x51\xcc\xb0\xf3\xe4\x0a\x11\x1f\xe4\x64\x5c\x8d\x1c\xf8\xdf\x87\x01\xc8\x60\x57\x01\xf4\x14\xdf\x69\x42\x43\x48\x6f\x55\x75\x06\x2c\x04\xfb\xe9\x8b\x2e\x7e\xf2\x37\xb6\x01\xe6\xfa\x2c\xe5\x6d\x3b\x7c\x9e\x01\xf0\xab\x02\xc8\xd2\x6e\xe2\x01\x60\x5e\xd2\x6f\x8e\x72\x5d\xaa\x58\x9b\x93\xfa\x42\x2b\xcf\x41\xd2\xb0\x27\xae\x05\x15\xd3\x7f\x8a\xf2\x85\xba\xb4\x7b\xb4\x9f\xf9\x7c\x4e\x4e\xfd\xef\xb8\xac\xed\x47\x80\xa5\xcc\xd5\xe3\x45\x66\xf6\xd0\x8f\x08\x42\x61\x8b\x23\x9d\x2d\xd8\x8b\x67\x93\xa2\x4a\xfc\xb0\xaf\x98\xa7\xfe\xe3\x17\x0b\xb8\xdb\x74\xef\x64\x9e\x0d\xb1\x3c\x2a\xed\x37\xec\x37\x15\x0d\x10\x12\x02\x57\x18\xcd", 240, { 0xf2, 0xa2, 0x37, 0xbc, 0x7f, 0x70, 0x10, 0xfc, 0x03, 0xb3, 0x3e, 0x9f, 0xf7, 0xfe, 0x5e, 0xda }, { 0x47, 0xde, 0x93, 0xb1, 0x2b, 0xfc, 0xf1, 0xdb, 0x97, 0x7a, 0xe0, 0x80, 0x77, 0x71, 0x39, 0x0f } },
{ "\x59\xca\xd8\x0c\xf6\x80\xb7\x5b\xed\x32\xed\x95\x9f\x5a\xe7\x33\xd9\xb0\x0d\x87\x9e\x34\x38\x1f\xf7\x7b\xb0\xa4\x83\xf1\x59\x4f\xb8\xcc\x74\x70\x65\x6f\x4d\xab\xcd\x35\xd9\x24\x97\xca\x15\x47\xad\x0c\x40\x8b\x9b\x4b\x5c\xb1\x7b\x46\x00\x56\xe1\x30\xd7\x59\x08\x5b\xc4\x83\xdc\xc3\x01\x93\xab\x3a\xa0\x10\x98\x60\x85\x56\x9d\xc1\xb4\x89\x34\x65\x07\x17\x91\xc6\x73\x12\x0f\xf5\x29\x93\x19\x2b\x5e\x65\x6e\x37\x81\x14\x6f\x30\xd1\xb7\xeb\x1f\x3a\x03\xb3\x07\x04\x68\xc4\xba\x1d\x6b\xa7\x07\xf2\x6e\xf0\x8c\x12\x8f\x1a\xdb\xa8\xd2\x3b\x70\x1e\x2a\xff\x1c\x44\x3a\xab\x3a\x5d\x9e\xf5\x59\x6b\xf9\x29\xd3\xcb\x97\xe7\x7d\x2d\x5d\xa0\x40\xa5\x17\x0f\xff\x8d\x1f\x3f\x43\xc1\xd1\xea\xe1\x39\xbe\x0c\x16\x93\xde\x51\x33\xe8\xf8\xda\xe3\x51\xd2\x86\x85\x0b\xc2\x49\x4a\xe5\x0a\x63\x67\x81\x24\x78\x51\xbc\x03\xda\xc6\xea\x18\xdc\xf4\xcb\xd6\x36\xb9\x5e\x97\x35\x41\x77\x02\xb7\x56\x06\x09\xd0\x48\x49\xef\xd0\x81\x50\x78\x21\x2e\x38\x24\xff\xa8\x69\x6d\xfc\x5f\x86\xfc\xcf", 241, { 0xc5, 0x27, 0x09, 0xb1, 0xdf, 0x61, 0x3f, 0x91, 0xab, 0x98, 0x07, 0xc2, 0x6d, 0x04, 0x98, 0x51 }, { 0x1c, 0x1b, 0x0e, 0x43, 0xed, 0xa9, 0xa2, 0x33, 0x19, 0x0f, 0x32, 0xa9, 0xef, 0x6c, 0xe4, 0x25 } },
{ "\x0c\x36\x85\x73\xd5\xc3\x33\x89\x46\x53\xd2\x2f\x05\x99\x0a\xe5\x54\xf4\x9f\x98\xb3\x58\x3c\x28\x2d\x15\x76\x05\x49\x99\x25\x38\x8b\x09\x4c\x73\xf2\x04\x1b\xf1\x79\x60\x14\x7a\x4c\x48\x8c\x87\xd8\xab\xaf\x43\xc9\xaf\xb9\x9a\xe8\x85\x1d\xe3\x38\x77\xd4\x65\x12\xef\xed\x5b\x46\x52\x4c\x90\x63\xa2\xcf\x4c\xec\xa6\x18\x04\x55\xe2\x90\xa3\x60\xef\x4f\xcf\x1f\x07\x76\x86\x96\x44\xf1\x89\x8a\x47\x9f\x7e\x1e\xad\x28\x29\xae\x0c\x4a\x36\xc9\xb8\x7f\x8a\x4d\x11\x72\x93\x5b\xf2\x1b\x9f\xd6\xee\xc5\xf1\xa4\x13\x81\x9b\x7c\x1a\xfe\xee\xd1\xa1\xe6\xeb\x55\x06\x78\xa9\x76\x34\x8f\x71\xb3\xf9\xc6\xc9\xa8\xd1\x6a\xef\xa5\x5f\xa3\x2b\xbd\x59\xc6\xef\xd7\x7f\x2c\x52\x39\x4d\xe6\x2f\xd9\x94\xa9\xb3\x48\x83\xb8\x59\xd5\x95\xbf\xab\x98\xc4\x86\x05\xff\x63\x11\xbb\xa2\xbd\xca\x00\xeb\x41\x49\xf6\x6b\x10\x90\x0f\x7a\x13\x8e\xb2\xa2\x73\x0e\x45\x61\x51\xb5\x53\x93\xf0\x5d\xe6\xf1\xa1\xd8\x16\xc1\x93\x5e\xc1\x59\xd3\x82\xb8\xf3\x3f\x8f\xa1\x87\xe7\x90\xf1\x9e\x45\xfd\x1f\xab\x2d", 242, { 0x9a, 0x2e, 0x13, 0xe7, 0xff, 0xb4, 0xc2, 0x3f, 0x6d, 0x4f, 0x8a, 0x4b, 0xb1, 0xc7, 0xcb, 0xfa }, { 0xa2, 0x79, 0x17, 0x1a, 0xdd, 0x01, 0x5d, 0xca, 0x80, 0x41, 0x9e, 0x26, 0x10, 0xad, 0xfa, 0x36 } },
{ "\x3d\x5f\x14\x88\x87\xef\x58\x67\x6d\x52\x52\x1d\xe2\x9d\x6c\x91\xee\xb2\x2b\x63\x30\x4e\x95\x2a\x92\x3a\x5d\x8e\xd6\x2d\xdc\xda\xd1\xe3\xed\xb0\xdf\x27\x3f\x5f\xee\x7e\xaf\x4c\xe9\x67\x80\xcf\xbd\x5a\xa2\xf5\x20\xec\x7b\x65\x79\x28\x7c\x46\xe6\x3e\x1a\xea\x70\x33\xdd\xa2\x1c\xee\x00\x01\x72\x3b\x6f\x71\x36\xc4\xea\xf3\x43\xb6\x8e\x1d\x1d\x55\xde\x2a\x20\xe9\x43\x1f\x1d\xda\xaa\x51\x74\x40\x27\xf0\x84\xef\x7b\x6d\x7d\xc1\x26\xd5\x34\x2a\x16\x5d\xbd\x0d\x50\x9e\x59\x31\x59\x22\x97\xee\x3c\x88\x77\xe4\x00\x30\x27\xb8\x2e\x19\x61\x31\xf1\xe4\x10\x73\xa5\x08\xfb\x53\xff\xa1\xb2\x38\x06\x1e\x25\x5b\x79\x84\x38\x73\xb9\xed\xf4\x1e\x3f\x9b\x77\x4a\x91\x13\xf9\x6d\x92\xaf\x78\x51\x6c\xd5\xe2\xd3\x80\xa7\x12\xd9\x74\x44\xa1\x3c\xc1\x80\x1a\xe9\x53\x5b\xed\x52\xfb\x1d\xf1\x3d\xe8\x0a\x42\xde\x13\x82\xec\xb9\xfd\xbc\x35\xc8\xd9\xa4\xc1\x88\x36\x85\x26\x43\xff\xdf\x1e\x41\xab\xb7\x48\x6f\x0a\x9e\xa0\xdf\xa5\xec\x90\x7a\x93\xfc\xeb\xeb\xca\x55\x95\x41\x3b\xa3\xb4\x98\x6c", 243, { 0x58, 0x9f, 0x49, 0x1f, 0x0d, 0xeb, 0x86, 0x8c, 0xad, 0x61, 0x4d, 0xc6, 0x90, 0xc2, 0x11, 0xf1 }, { 0x75, 0xee, 0x48, 0xeb, 0xc8, 0x99, 0x99, 0xce, 0x3f, 0x10, 0xa8, 0xc2, 0xe3, 0x9a, 0xe3, 0x9f } },
{ "\x18\x11\x9e\x69\xd2\xbe\x71\x93\xeb\x11\x77\x65\xc0\x8e\xcb\x6c\xbc\x71\x9d\xb9\x31\xc6\x40\x65\x58\xb7\x24\x6f\xeb\x57\x03\xde\x2c\x0b\x93\xdc\xcb\x1f\x71\x46\xac\xb9\xa1\xb2\x4c\x56\xd1\xaa\x93\xf0\x88\x2d\x1e\x75\x31\xa2\x63\x55\x5f\x37\x56\xb3\x72\xd6\x64\x5b\xfc\xff\x3d\xb8\xc8\xa5\xcf\x7f\x1d\x4c\xbc\x3c\x9b\xd9\xcf\x67\x31\x7a\x3a\x63\x62\xbc\x9d\x2d\x2d\x3e\xa9\x24\x01\xdd\x53\x37\xe1\xc1\xaa\x29\xd3\xb8\xae\xff\xd7\x8b\x2c\xdd\x24\xa5\xc9\x53\x6b\x0e\x26\xf8\x27\x59\x84\x20\x34\x76\xcc\x36\x64\x2d\x7c\xdb\x5f\x34\xd5\xbe\x85\xd4\x49\xe3\xea\x27\x14\x0f\x1e\xd5\xf0\x89\xc5\x01\x06\xed\xfb\x19\x69\xbe\x04\x56\x81\x63\x6a\x4c\x9d\x35\xb0\x2e\x9c\x58\xaa\xc9\x9a\x96\x90\x90\xf7\x84\xe0\x9e\x9f\x72\xc2\xf3\x5c\xae\x00\xdd\x95\x39\x3d\xb3\x87\x47\x41\x90\x1a\x6d\xee\x74\xa3\xd9\x95\x0e\x72\x91\x0f\x56\x7c\x35\x0b\xbe\x2f\x92\x77\x8d\x3f\xb4\x5f\x46\x18\x6a\x2b\x88\x6e\x7d\x90\xb5\xc4\xff\x3e\x14\x93\xf8\x37\xc1\xdb\xef\xcc\x3b\xf7\x0d\xfc\xad\x62\x7f\xe5\xf0", 244, { 0xba, 0xf4, 0xa4, 0x84, 0x75, 0x0a, 0xe3, 0xeb, 0x5f, 0x0d, 0x56, 0x17, 0xff, 0xe3, 0xb1, 0x61 }, { 0x6a, 0x89, 0xab, 0x83, 0xb2, 0x7c, 0xc3, 0x59, 0x36, 0xa9, 0xfa, 0x68, 0x9f, 0x52, 0xed, 0x7c } },
{ "\x03\x36\x9c\x3d\x33\x31\x84\xb6\x34\x96\xa9\xc1\xfa\x4e\xe2\x4f\xb1\xcc\x9e\xff\xc5\x88\x41\x93\x9e\x56\x4d\x37\x96\x48\xde\x6e\xb8\x57\x3c\x7e\xd4\x1c\x74\x52\xdc\xd0\x4a\x87\xa9\x5a\x87\xc0\xdb\x24\xa8\x30\xfb\xf5\x43\x8d\xcc\x71\xf0\xa3\xe6\x17\x62\x94\x42\xee\x6c\xcd\xcb\xf0\x12\x11\x52\xc5\x29\xd8\xab\x8b\x7d\x12\x91\x8d\x3b\x52\xca\xc5\xe8\x06\xec\xa4\x4f\x65\x05\xf7\x1c\x93\xdb\x19\x64\x23\xab\xb8\xbc\x63\xe3\x9c\xc1\x12\xc6\x49\x7c\xbb\xd2\xcd\x3e\x7e\x65\x8c\xd5\x9b\x23\x9f\xbe\xd1\x84\x68\xfb\xb6\x1d\x35\x87\xdd\x86\xcc\x79\xa3\x41\x8e\xfc\xe3\x9f\x15\x5e\x1c\x23\x6e\xe4\xf9\x7d\xc8\xa1\x9b\x6d\x3e\xce\xd4\xf8\xed\x39\x72\x7f\x82\xf5\xdd\xb4\x07\x45\x58\x04\x70\x59\x0b\x8b\xa5\xce\xdc\x55\x03\x14\x12\x7e\x7f\x90\x02\xa1\xbe\x42\x24\xad\xbd\xbb\xf2\x5e\x81\xc5\xa8\xcc\xaf\x0a\xd2\xef\x74\xc1\x2e\x79\xaf\xb6\xe9\x8c\x4d\xe1\x1d\xa6\xdd\xbb\xf8\xe4\x75\xda\xe7\x8e\xb2\xe1\xec\xf2\x43\xca\x04\xa5\x50\x1e\x92\x44\xf2\xbb\xe7\xc9\xe4\x04\x73\x1a\x4b\x3d\x2c\x11", 245, { 0x33, 0x63, 0xf2, 0x4d, 0xe2, 0x1a, 0xc1, 0xc7, 0x4f, 0xb7, 0x2e, 0x05, 0xa7, 0x37, 0xd9, 0xed }, { 0x16, 0xb6, 0x1e, 0x23, 0xb0, 0xe3, 0x84, 0x04, 0xcf, 0x90, 0xfd, 0x97, 0xbb, 0x31, 0x6b, 0x03 } },
{ "\xf9\xfc\x99\x14\xd9\xf1\x4a\x0b\x12\x2c\xde\xf1\x0a\xad\xb5\xdc\x1a\xa3\x8b\x48\x77\xb7\x13\x46\x11\x7f\x40\x35\x56\xf0\x4f\x2a\xf4\x36\x88\xa4\x76\xdc\x3f\x4b\xcc\x24\x8f\x37\xbf\x47\xe6\x0d\x82\x4d\x73\x17\xd2\x4b\xab\x32\xf8\xe6\xa2\x0e\xb4\xdd\x11\x5d\x6d\x07\x1c\x45\xf6\x4d\x1e\xab\x37\xee\x24\xa2\x3f\xce\x35\xf9\x58\xed\xbc\xe2\x7a\x5f\xc3\xd0\x99\x0b\x8a\x1a\x7c\x3d\x13\x8b\x53\x58\x07\x37\x06\xc3\x3d\xf2\x3c\x40\xb0\xe1\x42\xe3\x56\xe3\x81\x43\x8d\xc3\x25\xb1\x4f\x99\x6d\xee\x25\xb8\xdb\x85\xab\xd9\x56\xa2\x76\xec\x6b\xbb\x82\x0b\x0d\xfd\x5b\x33\xff\x8a\x16\xc8\x57\xb3\x64\x37\x21\x8f\xa5\x6c\x2d\xb2\xeb\x83\xa8\x19\xea\xd4\x95\x70\x54\x29\x7c\x48\x57\x2c\x42\xab\x0a\x24\x9a\x80\xf2\x30\xab\xf9\xe4\xf1\x51\x3d\x9a\x50\x38\x52\x32\xca\x9b\x7a\xba\x00\xfe\x86\x66\xac\xcf\x29\xf6\x8a\x24\xf1\x1c\x40\xe7\x81\xec\xb6\xea\x84\x5c\xcd\x19\x18\x91\xa8\x61\x67\x8a\xbb\xb8\xba\x89\x3b\xc3\x23\x55\x89\xcd\x28\x40\xa9\xb5\xbe\x56\x96\x21\x51\xe6\x4c\x38\xad\x46\x3d\xa7\xfa", 246, { 0x18, 0x88, 0x55, 0x6d, 0x13, 0x10, 0xc2, 0x9c, 0xa0, 0x48, 0x04, 0x0c, 0x5e, 0xab, 0x86, 0x0f }, { 0xfb, 0x22, 0xa6, 0x5d, 0xf3, 0xde, 0xef, 0x49, 0xec, 0x44, 0x53, 0xc7, 0xcb, 0x36, 0x2e, 0xef } },
{ "\x6d\xa1\xe5\x97\x60\xc8\x8b\x02\x7a\x4e\xe9\x5c\x5a\xc1\x03\x57\xb4\x8f\x41\x70\xdc\xfa\x39\xb6\x88\xaf\xec\x44\x87\x62\xee\x8a\xf1\x7e\x71\x19\x5a\xe8\x5d\xdb\xb1\xb4\x7a\x6f\x94\xbc\x93\x18\xbe\xce\xea\xa5\x04\xa7\xc5\x00\x0c\x48\xc2\x7a\xff\x38\xdc\xd3\xc5\x0c\x87\xa2\x49\x50\x0a\xbe\x7a\xba\x88\xf9\x9f\x33\x67\x96\x26\x1b\x59\x3f\xa5\xbf\xc0\x2f\x0d\x8f\xbc\x16\x2d\x11\xfc\xa8\x7c\xb0\x5b\xfa\x10\x54\x6b\x5e\x6d\x54\xad\xea\xf5\xc1\x05\x6f\xff\x06\xec\xa1\x42\xc0\x0a\x20\x0c\x76\xd6\x73\x5f\xdf\x78\x56\x99\x23\xe5\xd4\x3f\x99\x4c\x6c\xca\xe3\xd9\x82\xcd\x4a\x8a\xe6\xdd\x4e\xd6\xaf\x40\x1c\xa0\x4f\x5f\xcb\x4a\x5c\x32\x04\x17\x5b\xb4\x5f\x0e\xed\x59\x32\x90\x56\x0b\x0a\x56\x63\xb6\xbd\xa8\x1e\x92\x0a\x7b\x58\x1d\x40\xe7\x3e\x8a\xf6\xdb\xd8\x90\xfc\x9e\x33\x90\xc6\x97\xd0\x22\xde\xaf\x46\x37\xd6\x4c\x3e\x00\xaa\xfb\x08\xcc\xca\x21\x51\x4e\x9f\xeb\xa4\xea\x44\x68\x1e\x8e\x44\xc3\x03\x4e\x26\x7f\x0c\x12\x71\x8d\x36\x6a\x18\xeb\x74\x2a\xb9\xd2\x16\x27\xe0\x80\xa2\x9a\x78\x9f", 247, { 0x95, 0xb3, 0xb0, 0x3b, 0x97, 0xb7, 0xb1, 0x58, 0xb2, 0x07, 0x32, 0xcb, 0x75, 0x56, 0x68, 0x84 }, { 0x00, 0xe5, 0x84, 0xfe, 0x0c, 0x35, 0xe2, 0x26, 0x56, 0x0b, 0x62, 0x16, 0x85, 0xdb, 0xe3, 0x3d } },
{ "\x14\x3f\x42\xfc\x7c\xe7\x67\x42\xaf\x84\x74\xb3\xfa\x7b\x0a\x43\x93\x6a\x22\xc9\xca\x6a\x85\xab\x2c\x5f\x1c\x9e\xff\xd4\xfa\xa6\xf3\xe0\xee\x59\xa4\x00\xe1\x36\xe4\x8a\x60\xd7\x82\x77\xf7\x30\xfa\xe2\xac\x0e\x63\x13\x7e\xcd\x73\x1d\x2e\x17\xf3\x3f\x48\x36\xfc\xee\x6c\x49\xd7\x8a\x6c\x55\x39\x0f\x98\xe8\x03\x4f\xf2\xc6\xba\xdc\x56\x73\x90\x8d\x89\xff\x8c\x37\xe4\xfe\x51\xea\xc4\x04\x8d\xf8\xd5\xc4\x7f\x37\x01\x97\x85\x17\x68\x54\x73\x61\x32\x67\x7e\xcd\x75\xd3\xba\x3b\xcf\x5b\xb9\x3f\x9d\x2d\xfe\xe1\x93\xfc\x1d\xe8\x0e\x97\x0b\xd1\xd3\x1c\x6b\xaa\xee\x83\x05\x1e\xb4\x79\x23\xbe\x64\x5c\x7f\xf3\x64\x8d\xdf\x67\x3e\xe9\x75\x0a\x80\x63\x80\x25\xb9\xc5\xc3\xb6\x11\x85\x41\x76\x29\xfc\xe4\xe8\x25\x28\x53\x3b\x5a\x5c\x39\x48\x69\xcb\x01\x28\x31\x87\x6f\x28\x89\x01\x7f\xd0\x96\xd6\xfb\x90\xaa\x80\xe1\xee\x70\xd6\x3a\x66\x4c\xfa\xfa\xc8\xe0\x78\xf2\xb2\x59\x2a\x6b\xc9\xcf\x89\xa8\x8a\x62\x22\x50\xc4\x9d\x7d\xf6\xad\xb9\x2c\x0d\xef\x30\xa7\xa1\xff\x1c\x82\xb0\x57\x98\x47\x27\x53\x66\xba", 248, { 0xda, 0x88, 0xa3, 0xbf, 0x1e, 0xf6, 0xa0, 0x0a, 0xb9, 0x55, 0x9e, 0x6f, 0xef, 0x11, 0xf9, 0x20 }, { 0x7b, 0xad, 0x19, 0x64, 0xa8, 0x9a, 0x4e, 0x77, 0x16, 0x53, 0x28, 0x44, 0x87, 0x1f, 0x3f, 0x26 } },
{ "\x09\x8c\x07\x10\x93\x83\x6f\x26\x4a\x67\xf1\x7d\xa1\x00\xc8\x49\xd7\xce\xfd\x34\x78\x16\x47\xd5\x4f\xc3\x62\xed\x9c\x5c\xb3\xe8\x01\x80\x84\x0f\x1d\xc2\x8b\xcf\x74\x87\xca\x1e\x1e\x2d\x29\x23\x96\x1e\x08\x0e\x35\x18\xa5\x2c\x73\xc3\xd0\xc1\x15\x37\x81\xd1\xaf\xe7\x79\x87\x48\x04\xe4\x6b\x20\x00\x1e\xe1\xda\x07\x82\xdd\x6c\x77\x77\x38\x9e\x6f\xe9\xa7\x7f\x61\xcf\x51\x9c\x15\xf0\x0f\x0b\x3b\xe5\xe7\x90\x04\x4d\x18\x6a\x1c\x2a\x35\x3a\xb6\xe7\x5e\x39\x76\x31\x87\x7b\xa3\x48\x60\x51\xb1\x2e\x8f\xdb\x9c\xa7\x5a\xb3\x89\xb3\x30\xe2\x82\x7e\xcf\x36\xc4\x7b\x88\x3a\x5c\x84\x6c\x5e\xbb\x48\x5e\xc6\x10\x18\xa7\x15\xa2\x34\xfe\xe8\x92\x0f\xec\x7a\x53\x68\xe5\x1b\x10\x02\x44\xa2\xb1\xf6\x3e\xa1\xbf\x58\x17\xdf\x7c\x31\xa9\xef\x38\xe4\x4b\xc4\x2a\x63\xc5\x57\x0a\x1e\x09\xc4\x5a\xbd\x28\x7e\x26\x16\x6f\x13\xf1\x55\x91\xa1\x02\x93\x4f\x70\x68\x1e\x49\x89\x22\x7b\x7b\xa0\x7a\x66\x37\x27\x97\xe1\x93\x43\x22\x29\x1c\xb0\x4c\x70\x81\x54\xe3\xeb\xb5\xef\x34\xe4\x79\x44\xea\xae\x58\xf2\xc4\xd9\x17\x29", 249, { 0x37, 0xa4, 0x62, 0x45, 0x32, 0x28, 0x6e, 0x93, 0x4d, 0x1c, 0xdb, 0xec, 0x42, 0x26, 0x03, 0x40 }, { 0xae, 0x95, 0x35, 0x89, 0x21, 0xc4, 0xf7, 0xa9, 0x33, 0x99, 0x8b, 0xdd, 0x7a, 0x66, 0x99, 0xdf } },
{ "\x70\x84\x13\xd3\x6b\x3b\xf7\x1e\xd3\xde\x7e\x6b\x9e\x97\x50\x23\xc8\x20\x8b\xf1\xb9\xd0\x02\x37\x53\x46\xca\xd9\xce\xac\x57\x1f\x01\x57\x3e\x11\x1d\x4b\xad\x08\x81\x69\x83\x40\xbd\x13\xbc\x75\xa1\xce\x3e\x0c\x7c\xf6\x13\xa5\x14\xc2\xaa\x58\xf9\x1c\xc3\xab\xa8\xed\xce\x99\x9c\x52\x22\xa6\xd8\x85\xb6\x74\xae\x41\x94\xe2\x61\x34\xb7\x0f\x26\x25\x9a\xcc\x50\x62\xf3\x07\xe8\x5f\x2b\xa4\x1d\x0d\x9f\x8a\xc1\x8f\x1c\x0c\xa2\x8a\xbb\xdd\xfe\x5d\x3a\xb2\x0e\x07\xe0\xee\xb5\x94\x73\x29\xf8\xa3\x94\x67\x27\xc0\x77\x0a\x41\xa4\xb5\xce\x2d\xf0\x0e\x09\x4d\xe5\x8c\x5e\x31\xa8\xee\xcc\xd8\x39\xc5\x30\x6a\x5a\x3a\x1e\xb9\xb2\x5e\x7f\x07\xa9\x4a\x2d\x3f\x3e\xd2\x02\xef\x36\xa8\xa6\xaa\x9c\x61\xad\x7a\x30\x7d\xb1\x53\x9e\x76\x08\xe1\x7e\x1d\x60\x85\xc2\xe1\x7d\x43\x5f\xd7\xb2\xbb\xa5\xba\xb3\x2e\xbc\xbd\x95\x10\xcd\x4f\xec\x76\x9b\xd0\x3c\x82\xf6\x91\x30\xed\xd3\x02\xb2\x59\xc1\x3a\xed\x27\x68\xc6\xd8\xf0\xec\xb2\x86\xc1\x1d\xd2\x8b\x57\xb7\x13\x9c\x8b\x09\x0a\x53\x30\x03\x17\xf4\x30\x50\x8e\x79\x0a\x16", 250, { 0x23, 0x09, 0x45, 0xf8, 0x4d, 0x13, 0x5d, 0x4b, 0x2a, 0xfa, 0x81, 0x24, 0x6c, 0x8d, 0xa3, 0xcc }, { 0x04, 0x45, 0xf4, 0xb7, 0xf7, 0x0d, 0x15, 0xda, 0x9a, 0x94, 0xb9, 0x8f, 0x34, 0x94, 0x55, 0xac } },
{ "\xaa\xc8\x74\x1a\x38\xb7\x18\x20\x91\xcb\x6b\xc7\xa9\x9d\xe9\xae\x54\xcc\xa9\xca\x57\x92\x51\xb6\xaa\xb1\x3c\x2d\x7d\x0f\x64\xcf\x0b\x2c\x02\x59\xc3\x6f\xb4\xa6\xc7\xf1\x2c\xe0\x44\x7d\x7f\x2e\xad\x20\x62\xe7\x9c\xda\xeb\x64\x69\xac\xe0\xc9\x9c\x0c\x21\x4a\xf4\x5e\x2f\x6f\x23\x25\x40\x45\xc0\xdd\x6f\x29\x65\xfd\x87\x1a\x65\x6c\xea\xda\x8d\x68\xab\x8a\x6f\x05\xda\xda\x80\x4f\x85\x5d\x56\x03\x75\xd3\xa4\x7f\x0a\x94\xfb\x28\x77\x66\x15\xd7\x84\x32\xe9\x46\xde\x2e\xca\x81\x74\xdf\x53\xfb\xcd\xcd\x09\x38\xcf\x94\xd7\x50\x17\xbb\xa4\x66\x62\xce\x49\x79\x8c\xd3\x12\x73\x67\x06\x77\x2b\x3d\xa5\xbb\xe4\x02\x27\xc7\x73\xb4\x27\x27\xe6\xe7\x72\x07\x75\x07\x16\xb4\x90\x8c\x04\x05\x27\xa7\xcd\x76\x74\x82\xc6\xad\xb7\x26\x5c\xcf\xe4\x00\x1c\x5e\x35\x73\xca\xbe\xcc\x0c\xc7\xf7\x22\x6e\x12\xc7\xe5\x32\xe8\xfe\x4a\xb9\x0f\x51\x68\xed\xc7\x06\xea\x1e\x80\x3f\x60\x0c\x21\xe3\x81\xcf\xe1\x92\x27\xe8\x51\x62\xa5\xdc\xb2\x8d\x67\x03\x90\x2f\x37\xa6\xf6\x7a\xde\x85\x4c\xcf\xd8\x11\x37\x06\xb9\xc5\x06\x23\x12\x84", 251, { 0x66, 0x5f, 0xff, 0x3e, 0xec, 0xd6, 0xb9, 0x42, 0xf1, 0xee, 0xff, 0x90, 0x90, 0x86, 0xf9, 0x36 }, { 0xea, 0x40, 0xeb, 0x64, 0x66, 0x4a, 0x5e, 0x3b, 0x8d, 0xeb, 0x6b, 0xe4, 0x50, 0x73, 0x8e, 0x7a } },
{ "\x3a\x36\xb0\xbf\x37\x7d\xe2\xdf\x5f\x8c\x31\xc4\x65\x81\xca\x86\xb5\x0a\x97\x91\x4c\x66\x85\x8b\x36\x49\x36\xa7\x1f\xc4\x3a\x59\x5f\x63\xcc\xa4\xb7\xb0\x08\xcb\x2e\x91\xc9\xaa\xd2\xa1\xb3\xa6\x3a\x4f\xa0\xd7\xb6\xdf\xda\x63\x4a\x08\x5c\x09\x62\xf4\x3b\xd8\x39\x72\x94\x64\x7a\xf5\x35\xeb\x22\x53\xe0\x85\x93\xc0\x0b\x58\xf3\xc3\x88\x2b\x5b\x47\x4a\x82\x26\x03\x7e\xc2\xf4\xdb\xe2\x4b\x55\xc7\xc6\xbf\xb6\x56\x1d\x21\xed\x59\xd8\x91\x19\x14\x45\x63\xa3\x77\x11\xbc\xed\x58\x05\x6b\x39\x23\x8b\xc5\x76\xb2\x3a\x8c\x42\x6c\xbe\x9d\x9e\xb7\x48\xbf\x86\x90\x2b\x93\x0f\x46\x47\xf3\x20\xbc\x5c\xfb\xb8\xe5\x8a\x87\xa7\x9e\x67\xdc\x11\x46\x9a\x88\x18\xfd\x8f\x7e\x23\xc8\x67\x83\xd6\x31\x1a\xe9\x02\x6e\x7b\xdf\xd6\xfe\xb2\x61\x5d\xe4\xfa\x69\xbd\x80\xf4\x9a\x2e\xfd\xf6\xb9\x04\xa8\x0f\x7b\x7f\x9b\x10\x75\x16\xa4\x94\x6c\x05\x80\xc3\xa7\x84\x34\x8b\xb4\x72\x6f\x1c\xb9\x27\x98\xe9\xa9\xc5\xd3\x2d\xd9\xe0\x04\x39\x1b\x97\x00\x16\x49\x2a\x23\x26\x52\x80\xe5\x6d\x35\x67\xc8\xaf\x0f\x52\xb0\x26\xba\x48\x62\x80\x9e", 252, { 0x22, 0x6d, 0xf8, 0x35, 0xbd, 0xbf, 0xa7, 0x3e, 0xc9, 0x19, 0xa3, 0x6b, 0x8d, 0x18, 0x57, 0x25 }, { 0xa4, 0x1d, 0x80, 0x1b, 0x12, 0xca, 0xa6, 0xcf, 0x9a, 0xf5, 0xeb, 0x36, 0xed, 0x5e, 0x9a, 0xf4 } },
{ "\x4b\xda\xbe\xaa\xa1\xc6\x24\x5a\xb5\xeb\x18\xe3\x38\xc2\xc7\x65\xdb\x4f\x84\x4d\xea\x33\x72\xb9\xf4\x13\x79\x34\xd2\xa6\xa1\x98\x21\xbc\xb7\x93\x83\x9f\x5e\x39\xd0\x9c\xde\xb8\x86\x11\xbe\x24\x67\x03\x01\xf2\x17\x51\x02\x0a\xb5\x7f\xac\x6c\x2b\xdb\xb4\x89\xc9\xbc\x13\x2c\x19\xb0\x0f\x78\x92\x1e\x80\x30\x0f\xd7\x04\x6e\x50\xfa\x94\x92\x46\xcf\xa0\xb1\x65\x27\x21\x58\x9b\x6f\x80\x4b\x3b\x8e\x83\x57\xf0\x23\x4e\xea\x0d\x29\xfd\xb0\x1d\x13\xd6\x0b\x32\x75\xc1\xa6\x31\xed\x09\x0b\xfb\x20\xee\xd2\x23\xb0\x82\xaf\x58\x03\x12\x76\xc4\x3c\x0f\xbb\x94\xca\x58\xf5\x82\x1b\x5e\x9a\xe8\x6f\xc0\xa2\xb3\x67\xe4\x3b\x47\xc8\x6e\x53\x7a\x43\x98\x40\x71\x5f\xa3\x4d\x62\xb2\xed\x27\x94\xf0\x93\x0f\x54\xef\x97\xaf\x73\xcb\x88\x77\x05\xa9\xcd\x50\xe5\xa2\xf5\xfe\x5d\x76\xea\x31\x7f\xfa\x6e\xf2\xcb\x2c\xb0\xb9\xf5\x2c\x77\xf6\x07\xee\xeb\x48\xe1\x5c\x81\x25\xa6\xd2\xb0\x55\x9e\x91\xf5\x36\x84\x9c\x62\xbc\xd4\x36\x35\x2e\x6a\x3f\x47\x24\xf9\xda\x51\x4a\x90\xcd\x43\xcf\x4a\xcf\xa0\x31\x53\xbb\xcb\x8a\x1c\x03\xa7\x61\x63", 253, { 0x11, 0xd2, 0x45, 0x25, 0x40, 0xc5, 0xaf, 0x95, 0xd3, 0xf2, 0x5d, 0xba, 0xdc, 0xc0, 0xa1, 0x67 }, { 0x17, 0x17, 0x73, 0x50, 0x58, 0x8d, 0xfe, 0xd4, 0x13, 0xb7, 0x22, 0x77, 0x63, 0x98, 0x60, 0x92 } },
{ "\xca\x46\x32\x44\x65\xf3\x56\x68\x2f\x32\x33\x4a\xa8\x2a\x40\x1d\xe6\x2a\x13\x1d\x99\x50\x06\x2b\xae\xb3\x80\x55\x72\x35\x02\xd5\x85\x0a\x2a\x72\x57\x89\x24\x26\x11\x54\xf5\x8d\x3c\xb8\x84\x43\xaa\x61\xec\x5e\x78\xf9\x60\x93\xdf\x56\xec\x5b\x21\xae\x6a\x4a\x20\x30\x95\x68\x94\xd5\x65\x2c\xed\xf7\xf2\x65\x84\x79\xb6\x28\x9f\x84\x4c\xcc\x1b\xa6\x2e\x78\xa7\xb0\xa8\x03\x44\x66\xfd\x8d\x51\x48\xdd\x81\x00\x6c\x6a\xf1\x85\x0c\xc5\xf5\xc5\x8a\xc3\x6a\x25\xc0\x3d\x7b\x7b\xaf\xa2\xae\x1e\xf8\xcd\x7d\x17\x55\xd4\x3c\xf7\x0e\x9c\x7c\xa0\x17\xc8\x89\x74\xf6\x37\x94\x26\xf3\x08\x2e\x6d\x19\xa1\x9c\x4a\xd3\x69\x89\x41\x6c\x4a\xdb\x26\x92\x2b\x25\x08\x4b\xf8\x4a\xae\x7d\x9b\xd5\x69\x36\x7e\x4d\xc5\xf8\x41\x4d\x21\xa9\x7b\x4d\x87\x3a\x24\x7e\xd3\xf1\xf0\x79\xe3\x9c\x9b\x49\xe7\x5e\x68\x9a\xb7\x9c\x13\x5a\x4e\xe8\x32\xda\x5d\x79\xea\x49\xbd\xdb\x0c\x4d\x2a\xb1\x76\xf1\x72\x50\xa2\x0a\xc6\xe0\x8c\x7c\x04\x48\xb4\x17\x72\x3a\xc9\x60\x1b\xe1\xc3\x0c\x78\x30\x9d\x54\xd4\x8e\xba\x48\xb0\xfb\xf4\xa7\x1c\x1e\xe9\xbf\x78\xd5", 254, { 0x81, 0x31, 0x20, 0x63, 0x77, 0x78, 0xe5, 0x03, 0x16, 0x9e, 0x01, 0x91, 0xb5, 0x94, 0x6d, 0x17 }, { 0xbb, 0x48, 0xb0, 0x9a, 0x25, 0x25, 0x04, 0x63, 0x3b, 0x54, 0xf1, 0x41, 0x02, 0xa7, 0x02, 0xb0 } },
{ "\x80\x8c\x0b\x10\xd7\x08\xdc\x84\x3a\x07\x36\x56\xd9\x13\x02\x9f\x88\xb9\x6d\x57\x0e\xd6\x86\x9c\x19\x6c\xc7\x7b\x41\xc4\xaf\xd2\x92\x7c\x47\xc2\xe8\x21\xea\xc7\x60\xf9\xa9\x9f\x6c\x5c\x52\xf1\x87\x2b\x99\x30\xb0\xf0\x44\xc1\x4f\xbc\x06\x14\x3d\x10\xce\xa2\x6b\x65\x0d\x32\xcb\xb6\xf6\x48\xbf\x97\x73\x69\x5f\x8e\x1a\xac\x62\x2e\x5a\x40\xcc\xf3\x56\x1c\xe0\x3f\xc4\x97\xb2\x8d\xe1\xbf\x3e\x5c\xa6\x85\xba\xa7\xb7\x01\x05\x7f\x60\x11\x12\x1b\x7d\x04\x3e\x41\xc3\x5b\x11\x23\x4a\xfe\xe3\xbf\x97\x45\xc8\x7e\xf5\x63\xe4\xdf\x9a\xd9\x96\xbe\x56\x38\x1b\x71\x5c\x52\x6a\x14\x44\xd5\x74\x43\x86\xb8\xb3\x88\x67\xd2\xb4\x5c\x99\x3e\x63\x67\x8b\x80\xf5\xd6\x3c\x70\xeb\x8e\x1a\xb4\x75\xe6\xf0\x90\xc9\x57\x0c\xd4\x76\xc6\x42\xf8\xc5\x9a\x76\xc7\x89\x3b\x10\x5a\xde\x3e\x19\x67\x70\xca\x68\x79\x6c\x0b\x1d\x2e\x9c\x3e\x20\x17\xf1\xc4\x16\x5d\xa2\x42\xaf\xa5\x55\x93\x7c\x71\x9a\x66\x05\x10\x7a\xea\x68\xaf\x52\x3a\x4e\x66\x16\x70\xce\x54\x36\x98\xb4\x6a\x76\x2f\x88\x08\x05\x20\xfd\xa0\x87\x43\x43\x30\x9f\x5b\xc6\x71\x1e\x5a\xc1", 255, { 0x4a, 0x52, 0x36, 0x56, 0x39, 0x2e, 0xf0, 0x2f, 0xdd, 0x8b, 0x8a, 0x64, 0x35, 0x7f, 0xcb, 0x9d }, { 0x87, 0xe7, 0x8e, 0x84, 0xc3, 0xdf, 0xd4, 0xc2, 0xf2, 0x25, 0xe8, 0xa2, 0x91, 0x2e, 0x77, 0x54 } },
{ "\x7b\xb0\xc7\x8a\x1a\x46\xee\xd3\x56\x09\xb5\x59\x2c\x47\xee\xaa\x98\x2d\x84\x26\xc7\xde\x9b\x3c\x3b\xbb\x93\x5a\xd8\x47\x2d\x8e\x9c\xe6\xcb\xe5\x62\xb4\x14\xa4\xd0\xc3\xef\xb6\x8a\x83\x88\x32\x38\x4d\x61\x8f\x17\xb2\x9f\x4b\x63\xba\x44\xe5\x76\x7b\x4b\xd1\xda\xc1\xd7\xec\x26\xa5\x61\xf3\xb3\xa6\xd4\x4e\xda\x27\xb7\xfb\x38\xef\x67\x81\x82\xc7\x20\xf6\xe3\x92\x09\x4f\xa0\x0e\x9b\x3f\xdc\xcc\xeb\x68\x8a\x36\x25\xfb\x24\x92\x9f\xd9\xfa\xcc\xba\x62\xd7\xdf\xf4\x14\x7a\x80\x5f\xcb\xe8\x52\x57\x61\xa7\x5d\xe7\xba\x64\x6f\xaa\xdc\x57\x08\xcf\x06\xec\xbd\x02\x80\x58\x7b\xd6\x1f\x9b\xde\x00\xac\x99\xff\xde\x5e\x82\x79\x4b\xa3\x06\x20\x16\x01\x20\x34\x1d\x10\x15\x66\xd9\x69\xd9\xf5\x6e\xb6\xdc\x22\x6a\xa9\x1a\x04\xbe\xee\xbf\xbb\xb6\x63\x6b\x52\xc3\x27\x86\x1e\xc3\xc7\xe3\x9e\xf8\x1d\x86\x06\x21\x6d\x56\xac\x95\xb2\x4a\xf5\x1f\xd6\x4c\xa8\xfa\x88\xea\xa3\x77\x0a\x23\xb0\x8f\xbf\xef\x73\xf5\x9a\xca\xea\x21\x95\x13\xbe\x2d\xa0\xf0\x9d\x64\xd4\xf1\x88\x49\xe7\x99\x7b\x07\xa9\x47\x6d\x15\x4d\x6e\xdb\x02\xf0\x62\xac\xf7\x8c", 256, { 0xd5, 0x92, 0x92, 0xc0, 0xa0, 0x79, 0x76, 0x19, 0x89, 0xe9, 0x10, 0x1d, 0xe5, 0xa7, 0x06, 0x5b }, { 0x7d, 0x4b, 0x58, 0xd6, 0xe2, 0xc0, 0xd7, 0xd8, 0x4d, 0x31, 0x4f, 0xb4, 0xac, 0x2b, 0x9b, 0xf4 } },

File diff suppressed because it is too large Load diff

View file

@ -1,159 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
#ifndef PARITY_H
#define PARITY_H
#include "support.h"
#include "bw.h"
#include "state.h"
#include "io.h"
/****************************************************************************/
/* parity */
struct snapraid_split_handle {
char path[PATH_MAX]; /**< Path of the file. */
int f; /**< Handle of the files. */
struct stat st; /**< Stat info of the opened file. */
struct advise_struct advise; /**< Advise information. */
/**
* Size of the parity split.
* Only the latest not zero size is allowed to grow.
* Note that this value CANNOT be PARITY_SIZE_INVALID.
*/
data_off_t size;
/**
* Artificial size limit for testing.
* 0 means unlimited.
*/
data_off_t limit_size;
};
struct snapraid_parity_handle {
struct snapraid_split_handle split_map[SPLIT_MAX];
unsigned split_mac; /**< Number of parity splits. */
unsigned level; /**< Level of the parity. */
struct snapraid_bw* bw; /**< Context for bandwidth limiting. */
};
/**
* Compute the size of the allocated parity data in number of blocks.
*
* This includes parity blocks not yet written and still invalid.
*/
block_off_t parity_allocated_size(struct snapraid_state* state);
/**
* Compute the size of the used parity data in number of blocks.
*
* This includes only parity blocks used for files, not counting
* potential invalid parity at the end.
*
* If the array is fully synced there is no difference between
* parity_allocate_size() and parity_used_size().
* But if the sync is interrupted, the parity_used_size() returns
* the position of the latest BLK block, ignoring CHG, REL and DELETED ones,
* because their parity may be still not even written in the parity file.
*/
block_off_t parity_used_size(struct snapraid_state* state);
/**
* Report all the files outside the specified parity size.
*/
void parity_overflow(struct snapraid_state* state, data_off_t size);
/**
* Create the parity file.
* \param out_size Return the size of the parity file.
*/
int parity_create(struct snapraid_parity_handle* handle, const struct snapraid_parity* parity, unsigned level, int mode, uint32_t block_size, data_off_t limit_size);
/**
* Change the parity size.
*
* An elastic split that cannot reach the requested size may keep the size
* actually allocated and leave the remaining space to following splits.
* The resulting split layout is returned in parity.
*/
int parity_chsize(struct snapraid_parity_handle* handle, struct snapraid_parity* parity, int* is_modified, data_off_t size, uint32_t block_size, int skip_fallocate, int skip_space_holder);
/**
* Restore the parity split layout already stored in the handle, limited to size.
*
* Persisted split boundaries are preserved. If size ends inside the persisted
* layout, only its logical tail is removed: the containing split is shortened
* and all following splits are truncated to zero. If a split is physically
* non-empty, all preceding splits are restored to their exact logical size.
* The remaining physical tail is grown lazily by parity_write().
*/
int parity_restore(struct snapraid_parity_handle* handle, data_off_t size, uint32_t block_size, int skip_fallocate);
/**
* Get the size of the parity.
*
* This returns the cached/expected version of the split sizes, and not the real file size.
*/
void parity_size(struct snapraid_parity_handle* handle, data_off_t* out_size);
/**
* Get the physical size of the logical parity file across splits.
*
* This composes the physical EOF of consecutive splits within their logical
* boundaries. If an earlier split is physically shorter than its logical size,
* later splits cannot extend the logical offset past that missing region.
*
* Physical presence does not imply parity validity. Parity may be invalid,
* stale, unwritten, sparse, or contain holes independently of its physical EOF.
*/
void parity_physical_size(struct snapraid_parity_handle* handle, data_off_t* out_size);
/**
* Open an already existing parity file.
*/
int parity_open(struct snapraid_parity_handle* handle, const struct snapraid_parity* parity, unsigned level, int mode, uint32_t block_size, data_off_t limit_size);
/**
* Flush the parity file in the disk.
*/
int parity_sync(struct snapraid_parity_handle* handle);
/**
* Close the parity file.
*/
int parity_close(struct snapraid_parity_handle* handle);
/**
* Read a block from the parity file.
*/
int parity_read(struct snapraid_parity_handle* handle, block_off_t pos, unsigned char* block_buffer, unsigned block_size);
/**
* Write a block in the parity file.
*/
int parity_write(struct snapraid_parity_handle* handle, block_off_t pos, unsigned char* block_buffer, unsigned block_size, int skip_fallocate);
/**
* Wait for all scheduled read-ahead before writing content state.
* state_write() bypasses extent locks and may remove obsolete extents, while
* reader workers look up extents and update fs_last. They must finish first to
* avoid races. Completed results remain queued for later use.
*/
void state_read_barrier(struct snapraid_io* io);
/**
* Establish the durability and read-ahead barrier before publishing sync state.
* Wait for parity writes and reject writer errors, then sync the parity files.
* Content must not record completed BLK/EMPTY states until their parity is
* durable. Finally wait for read-ahead so state_write() can access extent trees
* without racing reader workers; completed results remain queued for later use.
*
* If io is 0, only the parity files are synced. Return -1 on a write or sync
* failure; the caller must not publish completed state in that case.
*/
int state_write_barrier(struct snapraid_state* state, struct snapraid_io* io, struct snapraid_parity_handle* parity_handle, block_off_t blockcur);
#endif

View file

@ -1,469 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2013 Andrea Mazzoleni
#include "os/portable.h"
#include "support.h"
#include "elem.h"
#include "state.h"
struct snapraid_pool {
char file[PATH_MAX];
char linkto[PATH_MAX];
int64_t mtime_sec;
int mtime_nsec;
/* nodes for data structures */
tommy_hashdyn_node node;
};
struct snapraid_pool* pool_alloc(const char* dir, const char* name, const char* linkto, const struct stat* st)
{
struct snapraid_pool* pool;
pool = malloc_nofail(sizeof(struct snapraid_pool));
pathprint(pool->file, sizeof(pool->file), "%s%s", dir, name);
pathcpy(pool->linkto, sizeof(pool->linkto), linkto);
pool->mtime_sec = st->st_mtime;
pool->mtime_nsec = STAT_NSEC(st);
return pool;
}
static inline tommy_hash_t pool_hash(const char* file)
{
#if TOMMY_SIZE_BIT == 64
return tommy_hash_u64(0, file, strlen(file));
#else
return tommy_hash_u32(0, file, strlen(file));
#endif
}
static void pool_free(void* void_pool)
{
struct snapraid_pool* pool = void_pool;
free(pool);
}
int pool_compare(const void* void_arg, const void* void_data)
{
const char* arg = void_arg;
const struct snapraid_pool* pool = void_data;
return strcmp(arg, pool->file);
}
/**
* Remove empty dir.
* Return == 0 if the directory is empty, and it can be removed
*/
static int clean_dir(const char* dir)
{
DIR* d;
int full = 0;
d = opendir(dir);
if (!d) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error opening pool directory '%s'. %s.\n", dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
while (1) {
char path_next[PATH_MAX];
struct stat st;
const char* name;
struct dirent* dd;
/* clear errno to detect erroneous conditions */
errno = 0;
dd = readdir(d);
if (dd == 0 && errno != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error reading pool directory '%s'. %s.\n", dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (dd == 0) {
break; /* finished */
}
/* skip "." and ".." files */
name = dd->d_name;
if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
continue;
pathprint(path_next, sizeof(path_next), "%s%s", dir, name);
#if HAVE_STRUCT_DIRENT_D_STAT
/* convert dirent to lstat result */
dirent_lstat(dd, &st);
/*
* If the st_mode field is missing, takes care to fill it using normal lstat()
* at now this can happen only in Windows
*/
if (st.st_mode == 0) {
if (lstat(path_next, &st) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error in stat file/directory '%s'. %s.\n", path_next, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
#else
/* get lstat info about the file */
if (lstat(path_next, &st) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error in stat file/directory '%s'. %s.\n", path_next, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
#endif
if (S_ISDIR(st.st_mode)) {
/* recurse */
pathslash(path_next, sizeof(path_next));
if (clean_dir(path_next) == 0) {
int ret;
/* directory is empty, try to remove it */
ret = rmdir(path_next);
if (ret < 0) {
#ifdef _WIN32
if (errno == EACCES) {
/*
* In Windows just ignore EACCES errors removing directories
* because it could happen that the directory is in use
* and it cannot be removed
*/
log_fatal(errno, "Directory '%s' not removed because it's in use.\n", path_next);
full = 1;
} else
#endif
{
/* LCOV_EXCL_START */
log_fatal(errno, "Error removing pool directory '%s'. %s.\n", path_next, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
} else {
/* something is present */
full = 1;
}
} else {
/* something is present */
full = 1;
}
}
if (closedir(d) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error closing pool directory '%s'. %s.\n", dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
return full;
}
/**
* Read all the links in a directory tree.
*/
static void read_dir(tommy_hashdyn* poolset, const char* base_dir, const char* sub_dir)
{
char dir[PATH_MAX];
DIR* d;
pathprint(dir, sizeof(dir), "%s%s", base_dir, sub_dir);
d = opendir(dir);
if (!d) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error opening pool directory '%s'. %s.\n", dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
while (1) {
char path_next[PATH_MAX];
struct stat st;
const char* name;
struct dirent* dd;
/* clear errno to detect erroneous conditions */
errno = 0;
dd = readdir(d);
if (dd == 0 && errno != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error reading pool directory '%s'. %s.\n", dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (dd == 0) {
break; /* finished */
}
/* skip "." and ".." files */
name = dd->d_name;
if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
continue;
pathprint(path_next, sizeof(path_next), "%s%s", dir, name);
#if HAVE_STRUCT_DIRENT_D_STAT
/* convert dirent to lstat result */
dirent_lstat(dd, &st);
/*
* If the st_mode field is missing, takes care to fill it using normal lstat()
* at now this can happen only in Windows
*/
if (st.st_mode == 0) {
if (lstat(path_next, &st) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error in stat file/directory '%s'. %s.\n", path_next, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
#else
/* get lstat info about the file */
if (lstat(path_next, &st) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error in stat file/directory '%s'. %s.\n", path_next, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
#endif
if (S_ISLNK(st.st_mode)) {
struct snapraid_pool* pool;
char linkto[PATH_MAX];
ssize_t ret;
ret = readlink(path_next, linkto, sizeof(linkto));
if (ret < 0 || ret >= PATH_MAX) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error in readlink symlink '%s'. %s.\n", path_next, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
linkto[ret] = 0;
/* store the link info */
pool = pool_alloc(sub_dir, name, linkto, &st);
tommy_hashdyn_insert(poolset, &pool->node, pool, pool_hash(pool->file));
} else if (S_ISDIR(st.st_mode)) {
pathprint(path_next, sizeof(path_next), "%s%s/", sub_dir, name);
read_dir(poolset, base_dir, path_next);
} else {
msg_verbose("Ignoring pool file '%s'\n", path_next);
}
}
if (closedir(d) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error closing pool directory '%s'. %s.\n", dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
/**
* Remove the link
*/
static void remove_link(void* void_arg, void* void_pool)
{
char path[PATH_MAX];
const char* arg = void_arg;
struct snapraid_pool* pool = void_pool;
int ret;
pathprint(path, sizeof(path), "%s%s", arg, pool->file);
/* delete the link */
ret = remove(path);
if (ret < 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error removing symlink '%s'. %s.\n", path, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
/**
* Create a link to the specified disk link.
*/
static void make_link(tommy_hashdyn* poolset, const char* pool_dir, const char* share_dir, struct snapraid_disk* disk, const char* sub, int64_t mtime_sec, int mtime_nsec)
{
char path[PATH_MAX];
char linkto[PATH_MAX];
char linkto_exported[PATH_MAX];
struct snapraid_pool* found;
int ret;
/* make the source path */
pathprint(path, sizeof(path), "%s%s", pool_dir, sub);
/* make the linkto path */
if (share_dir[0] != 0) {
/* with a shared directory, use it */
pathprint(linkto, sizeof(linkto), "%s%s/%s", share_dir, disk->name, sub);
} else {
/* without a share directory, use the local disk paths */
pathprint(linkto, sizeof(linkto), "%s%s", disk->dir, sub);
}
/* search for the sub path */
found = tommy_hashdyn_search(poolset, pool_compare, sub, pool_hash(sub));
if (found) {
/* remove from the set */
tommy_hashdyn_remove_existing(poolset, &found->node);
/* check if the info match */
if (found->mtime_sec == mtime_sec
&& found->mtime_nsec == mtime_nsec
&& strcmp(found->linkto, linkto) == 0
) {
/* nothing to do */
pool_free(found);
return;
}
/* delete the link */
ret = remove(path);
if (ret < 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error removing symlink '%s'. %s.\n", path, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
pool_free(found);
}
/* create the ancestor directories */
ret = mkancestor(path);
if (ret != 0) {
/* LCOV_EXCL_START */
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
/* convert back slashes */
pathexport(linkto_exported, sizeof(linkto_exported), linkto);
/* create the symlink */
ret = symlink(linkto_exported, path);
if (ret != 0) {
if (errno == EEXIST) {
log_error(errno, "WARNING! Pool path '%s' already exists\n", path);
return;
#ifdef _WIN32
} else if (errno == EPERM) {
/* LCOV_EXCL_START */
log_fatal(errno, "You must run as Administrator to be able to create symlinks.\n");
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
#endif
} else {
/* LCOV_EXCL_START */
log_fatal(errno, "Error writing symlink '%s'. %s.\n", path, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
if (mtime_sec) {
ret = lmtime(path, mtime_sec, mtime_nsec);
if (ret != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error setting time to symlink '%s'. %s.\n", path, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
}
void state_pool(struct snapraid_state* state)
{
tommy_hashdyn poolset;
tommy_node* i;
char pool_dir[PATH_MAX];
char share_dir[PATH_MAX];
unsigned count;
tommy_hashdyn_init(&poolset);
if (state->pool[0] == 0) {
/* LCOV_EXCL_START */
log_fatal(EUSER, "To use the 'pool' command you must set the pool directory in the configuration file\n");
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
msg_progress("Reading...\n");
/* pool directory with final slash */
pathprint(pool_dir, sizeof(pool_dir), "%s", state->pool);
pathslash(pool_dir, sizeof(pool_dir));
/* share directory with final slash */
pathprint(share_dir, sizeof(share_dir), "%s", state->share);
pathslash(share_dir, sizeof(share_dir));
/* first read the previous pool tree */
read_dir(&poolset, pool_dir, "");
msg_progress("Writing...\n");
/* for each disk */
count = 0;
for (i = state->disklist; i != 0; i = i->next) {
tommy_node* j;
struct snapraid_disk* disk = i->data;
/* for each file */
for (j = disk->filelist; j != 0; j = j->next) {
struct snapraid_file* file = j->data;
make_link(&poolset, pool_dir, share_dir, disk, file->sub, file->mtime_sec, file->mtime_nsec);
++count;
}
/* for each link */
for (j = disk->linklist; j != 0; j = j->next) {
struct snapraid_link* slink = j->data;
make_link(&poolset, pool_dir, share_dir, disk, slink->sub, 0, 0);
++count;
}
/* we ignore empty dirs in disk->dir */
}
msg_progress("Cleaning...\n");
/* delete all the remaining links */
tommy_hashdyn_foreach_arg(&poolset, remove_link, pool_dir);
/* delete empty dirs */
clean_dir(pool_dir);
tommy_hashdyn_foreach(&poolset, pool_free);
tommy_hashdyn_done(&poolset);
if (count)
msg_status("%u links\n", count);
else
msg_status("No link\n");
log_tag("summary:link_count:%u\n", count);
log_tag("summary:exit:ok\n");
log_flush();
}

View file

@ -1,107 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2013 Andrea Mazzoleni
#include "os/portable.h"
#include "util.h"
#include "elem.h"
#include "import.h"
#include "state.h"
#include "parity.h"
#include "handle.h"
#include "raid/raid.h"
/****************************************************************************/
/* rehash */
void state_rehash(struct snapraid_state* state)
{
block_off_t blockmax;
block_off_t i;
int has_pending_dealloc = 0;
blockmax = parity_allocated_size(state);
/* check if a rehash is already in progress */
if (state->prevhash != HASH_UNDEFINED) {
/* LCOV_EXCL_START */
log_tag("summary:exit:already_in_progress\n");
log_fatal(EUSER, "You already have a rehash in progress.\n");
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (state->hash == state->besthash) {
/* LCOV_EXCL_START */
log_tag("summary:exit:not_required\n");
log_fatal(EUSER, "You are already using the best hash for your platform.\n");
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
/* deleted-only positions are not counted in unsynced_blocks, but their hashes still need the current generation */
for (tommy_node* node = state->disklist; node != 0; node = node->next) {
struct snapraid_disk* disk = node->data;
if (!tommy_list_empty(&disk->dealloclist)) {
has_pending_dealloc = 1;
break;
}
}
/* a rehash can start only from a fully synchronized state */
if (state->unsynced_blocks != 0 || has_pending_dealloc) {
/* LCOV_EXCL_START */
log_tag("summary:exit:sync_required\n");
log_fatal(EUSER, "You cannot start a rehash with an incomplete sync.\n");
log_fatal(EUSER, "Run 'snapraid sync' first.\n");
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
/* copy the present hash as previous one */
state->prevhash = state->hash;
memcpy(state->prevhashseed, state->hashseed, HASH_MAX);
/* set the new hash and seed */
state->hash = state->besthash;
if (os_randomize(state->hashseed, HASH_MAX) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Failed to get random values.\n");
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
/* mark all the block for rehashing */
for (i = 0; i < blockmax; ++i) {
snapraid_info info;
/* if it's unused */
info = info_get(&state->infoarr, i);
if (info == 0) {
/* skip it */
continue;
}
if (info_get_rehash(info)) {
/* LCOV_EXCL_START */
log_fatal(EINTERNAL, "Internal inconsistency for a rehash already in progress\n");
os_abort();
/* LCOV_EXCL_STOP */
}
/* enable the rehash */
info = info_set_rehash(info);
/* save it */
info_set(&state->infoarr, i, info);
}
/* save the new content file */
state->need_write = 1;
msg_status("A rehash is now scheduled. It will take place progressively in the next\n");
msg_status("'sync' and 'scrub' commands. You can check the rehash progress using the\n");
msg_status("'status' command.\n");
log_tag("summary:exit:scheduled\n");
}

View file

@ -1,40 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- SnapRAID Windows Daemon Manifest -->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="*"
name="snapraid"
type="win32"
/>
<description>SnapRAID CLI</description>
<!-- UAC PRIVILEGES: Uses 'asInvoker' because 'requireAdministrator' force a new console window to open -->
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<!-- OS COMPATIBILITY: Declares support for Win 10/11 to prevent 'Version Lying'. -->
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<!-- Enables paths longer than 260 characters for deep backup trees. -->
<longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
<!-- Sets ANSI code page to UTF-8 so fopen() works like it does on Linux. -->
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
<!-- Enables the more efficient Segment Heap. -->
<heapType xmlns="http://schemas.microsoft.com/SMI/2020/WindowsSettings">SegmentHeap</heapType>
</windowsSettings>
</application>
</assembly>

View file

@ -1,35 +0,0 @@
#include <windows.h>
#include "config.h"
1 RT_MANIFEST "resource.manifest"
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEFLAGSMASK 0x3fL
FILEFLAGS 0x0L
FILEOS VOS_NT_WINDOWS32
FILETYPE VFT_APP
FILESUBTYPE 0x0L
BEGIN
BLOCK "StringFileInfo"
BEGIN
// 0409 = US English; 04b0 = Unicode (UTF-16)
BLOCK "040904b0"
BEGIN
VALUE "CompanyName", "Andrea Mazzoleni"
VALUE "FileDescription", "SnapRAID CLI"
VALUE "FileVersion", PACKAGE_VERSION
VALUE "InternalName", "snapraid"
VALUE "LegalCopyright", "Copyright (C) 2026 Andrea Mazzoleni"
VALUE "OriginalFilename", "snapraid.exe"
VALUE "ProductName", "SnapRAID"
VALUE "ProductVersion", PACKAGE_VERSION
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409, 1200
END
END

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,365 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2014 Andrea Mazzoleni
#include "os/portable.h"
#include "support.h"
#include "search.h"
#ifndef _WIN32
static const char* es(int err)
{
if (is_hw(err))
return "error_io";
else
return "error";
}
#endif
/****************************************************************************/
/* search */
static void search_file(struct snapraid_state* state, const char* path, data_off_t size, int64_t mtime_sec, int mtime_nsec)
{
struct snapraid_search_file* file;
tommy_hash_t file_hash;
file = malloc_nofail(sizeof(struct snapraid_search_file));
file->path = strdup_nofail(path);
file->size = size;
file->mtime_sec = mtime_sec;
file->mtime_nsec = mtime_nsec;
file_hash = file_stamp_hash(file->size, file->mtime_sec, file->mtime_nsec);
tommy_hashdyn_insert(&state->searchset, &file->node, file, file_hash);
}
void search_file_free(void* void_file)
{
struct snapraid_search_file* file = void_file;
free(file->path);
free(file);
}
struct search_file_compare_arg {
const struct snapraid_state* state;
const struct snapraid_block* block;
const struct snapraid_file* file;
unsigned char* buffer;
data_off_t offset;
size_t read_size;
int prevhash;
};
int search_file_compare(const void* void_arg, const void* void_data)
{
const struct search_file_compare_arg* arg = void_arg;
const struct snapraid_search_file* file = void_data;
const struct snapraid_state* state = arg->state;
unsigned char buffer_hash[HASH_MAX];
const char* path = file->path;
int f;
ssize_t ret;
size_t count;
/* compare file info */
if (arg->file->size != file->size)
return -1;
if (arg->file->mtime_sec != file->mtime_sec)
return -1;
if (arg->file->mtime_nsec != file->mtime_nsec)
return -1;
/* read the block and compare the hash */
f = open(path, O_RDONLY | O_BINARY);
if (f == -1) {
if (errno == ENOENT)
log_error(EUSER, "WARNING! Search candidate file '%s' disappeared.\n", path);
else
log_error(errno, "WARNING! Error opening search candidate '%s'. %s.\n", path, strerror(errno));
return -1;
}
count = 0;
do {
ret = pread(f, (char*)arg->buffer + count, arg->read_size - count, arg->offset + count);
if (ret < 0) {
if (errno == EINTR)
continue;
log_error(errno, "WARNING! Error reading search candidate '%s'. %s.\n", path, strerror(errno));
if (close(f) != 0)
log_error(errno, "WARNING! Error closing search candidate '%s'. %s.\n", path, strerror(errno));
return -1;
}
if (ret == 0) {
log_error(EUSER, "WARNING! Unexpected end of file in search candidate '%s'.\n", path);
if (close(f) != 0)
log_error(errno, "WARNING! Error closing search candidate '%s'. %s.\n", path, strerror(errno));
return -1;
}
count += ret;
} while (count < arg->read_size);
ret = close(f);
if (ret != 0) {
log_error(errno, "WARNING! Error closing search candidate '%s'. %s.\n", path, strerror(errno));
return -1;
}
if (arg->read_size != state->block_size) {
/* fill the remaining with 0 */
memset(arg->buffer + arg->read_size, 0, state->block_size - arg->read_size);
}
/* compute the block hash from the canonical buffer */
if (arg->prevhash)
memhash_block(state->prevhash, state->prevhashseed, buffer_hash, arg->buffer, arg->read_size, state->block_size);
else
memhash_block(state->hash, state->hashseed, buffer_hash, arg->buffer, arg->read_size, state->block_size);
/* check if the hash is matching */
if (memcmp(buffer_hash, arg->block->hash, BLOCK_HASH_SIZE) != 0)
return -1;
return 0;
}
int state_search_fetch(struct snapraid_state* state, int prevhash, struct snapraid_file* missing_file, block_off_t missing_file_pos, struct snapraid_block* missing_block, unsigned char* buffer)
{
struct snapraid_search_file* file;
tommy_hash_t file_hash;
struct search_file_compare_arg arg;
arg.state = state;
arg.block = missing_block;
arg.file = missing_file;
arg.buffer = buffer;
arg.offset = state->block_size * missing_file_pos;
arg.read_size = file_block_size(missing_file, missing_file_pos, state->block_size);
arg.prevhash = prevhash;
file_hash = file_stamp_hash(arg.file->size, arg.file->mtime_sec, arg.file->mtime_nsec);
/* search in the hashtable, and also check if the data matches the hash */
file = tommy_hashdyn_search(&state->searchset, search_file_compare, &arg, file_hash);
if (!file)
return -1;
/* if found, buffer is already set with data */
return 0;
}
static void search_dir(struct snapraid_state* state, struct snapraid_disk* disk, const struct fsidentity* root_identity, const char* dir, const char* sub)
{
DIR* d;
size_t mount_point_len = disk != 0 ? strlen(disk->mount_point) : 0;
size_t sub_len = strlen(sub);
d = opendir(dir);
if (!d) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error opening directory '%s'. %s.\n", dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
while (1) {
char path_next[PATH_MAX];
char sub_next[PATH_MAX];
char out[PATH_MAX];
struct snapraid_filter* reason = 0;
struct stat st;
const char* name;
struct dirent* dd;
/* clear errno to detect erroneous conditions */
errno = 0;
dd = readdir(d);
if (dd == 0 && errno != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error reading directory '%s'. %s.\n", dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (dd == 0) {
break; /* finished */
}
/* skip "." and ".." files */
name = dd->d_name;
if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0)))
continue;
pathprint(path_next, sizeof(path_next), "%s%s", dir, name);
pathprint(sub_next, sizeof(sub_next), "%s%s", sub, name);
/* exclude hidden files even before calling lstat() */
if (disk != 0 && filter_hidden(state->filter_hidden, dd) != 0) {
if (pathcmp(".snapraidignore", dd->d_name) != 0) {
msg_verbose("Excluding hidden '%s'\n", path_next);
continue;
}
}
/* exclude content files even before calling lstat() */
if (disk != 0 && filter_content(&state->contentlist, disk->mount_point, mount_point_len, sub, sub_len, name) != 0) {
msg_verbose("Excluding content '%s'\n", path_next);
continue;
}
/* exclude snapshot container even before calling lstat() */
if (disk != 0 && filter_snapshot(state->snapshot, sub, name) != 0) {
msg_verbose("Excluding snapshots directory '%s'\n", path_next);
continue;
}
#if HAVE_STRUCT_DIRENT_D_STAT
/* convert dirent to lstat result */
dirent_lstat(dd, &st);
/*
* If the st_mode field is missing, takes care to fill it using normal lstat()
* at now this can happen only in Windows (with HAVE_STRUCT_DIRENT_D_STAT defined),
* because we use a directory reading method that doesn't read info about ReparsePoint.
* Note that here we cannot call here lstat_sync(), because we don't know what kind
* of file is it, and lstat_sync() doesn't always work
*/
if (st.st_mode == 0) {
if (lstat(path_next, &st) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error in stat file/directory '%s'. %s.\n", path_next, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
#else
/* get lstat info about the file */
if (lstat(path_next, &st) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error in stat file/directory '%s'. %s.\n", path_next, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
#endif
if (S_ISREG(st.st_mode)) {
if (disk == 0
|| pathcmp(".snapraidignore", name) == 0
|| filter_path(&state->filterlist, &reason, disk->name, sub_next) == 0) {
search_file(state, path_next, st.st_size, st.st_mtime, STAT_NSEC(&st));
} else {
msg_verbose("Excluding file '%s' for rule '%s'\n", path_next, filter_type(reason, out, sizeof(out)));
}
} else if (S_ISDIR(st.st_mode)) {
if (disk == 0 || filter_subdir(&state->filterlist, &reason, disk->name, sub_next) == 0) {
#ifndef _WIN32
/*
* Automatic array search must stay within the same filesystem,
* mount, and subvolume boundaries as the normal data-disk scan.
* Explicit -i imports pass no root identity and may cross them.
*/
if (root_identity) {
struct fsidentity identity;
if (fsidentity(path_next, &st, &identity) != 0) {
/* LCOV_EXCL_START */
log_tag("%s:%u:%s:%s: Statx error. %s.\n", es(errno), 0, disk->name, esc_tag(path_next), strerror(errno));
log_fatal(errno, "Error accessing directory '%s'. %s.\n", path_next, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (identity.device != root_identity->device) {
log_tag("%s:%u:%s:%s: Ignoring mount point.\n", es(ESOFT), 0, disk->name, esc_tag(path_next));
log_error(ESOFT, "WARNING! Ignoring mount point '%s' because it appears to be in a different device\n", path_next);
continue;
} else if (identity.mnt_id != root_identity->mnt_id) {
log_tag("%s:%u:%s:%s: Ignoring mount point.\n", es(ESOFT), 0, disk->name, esc_tag(path_next));
log_error(ESOFT, "WARNING! Ignoring mount point '%s' because it belongs to a different mount\n", path_next);
continue;
} else if (identity.subvol != root_identity->subvol) {
log_tag("%s:%u:%s:%s: Ignoring nested subvolume.\n", es(ESOFT), 0, disk->name, esc_tag(path_next));
log_error(ESOFT, "WARNING! Ignoring nested subvolume '%s' because it belongs to a different subvolume\n", path_next);
continue;
}
}
#endif
pathslash(path_next, sizeof(path_next));
pathslash(sub_next, sizeof(sub_next));
search_dir(state, disk, root_identity, path_next, sub_next);
} else {
msg_verbose("Excluding directory '%s' for rule '%s'\n", path_next, filter_type(reason, out, sizeof(out)));
}
}
}
if (closedir(d) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Error closing directory '%s'. %s.\n", dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
void state_search(struct snapraid_state* state, const char* dir)
{
char path[PATH_MAX];
msg_progress("Importing...\n");
/* add the final slash */
pathimport(path, sizeof(path), dir);
pathslash(path, sizeof(path));
search_dir(state, 0, 0, path, "");
}
void state_search_array(struct snapraid_state* state)
{
tommy_node* i;
/* import from all the disks */
for (i = state->disklist; i != 0; i = i->next) {
struct snapraid_disk* disk = i->data;
/* skip data disks that are not accessible */
if (disk->skip_access)
continue;
msg_progress("Searching disk %s...\n", disk->name);
#ifndef _WIN32
struct stat st;
struct fsidentity identity;
if (lstat(disk->dir, &st) != 0) {
/* LCOV_EXCL_START */
log_tag("%s:%u:%s:%s: Stat error. %s.\n", es(errno), 0, disk->name, esc_tag(disk->dir), strerror(errno));
log_fatal(errno, "Error accessing directory '%s'. %s.\n", disk->dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
if (fsidentity(disk->dir, &st, &identity) != 0) {
/* LCOV_EXCL_START */
log_tag("%s:%u:%s:%s: Statx error. %s.\n", es(errno), 0, disk->name, esc_tag(disk->dir), strerror(errno));
log_fatal(errno, "Error accessing directory '%s'. %s.\n", disk->dir, strerror(errno));
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
search_dir(state, disk, &identity, disk->dir, "");
#else
search_dir(state, disk, 0, disk->dir, "");
#endif
}
}

View file

@ -1,50 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2014 Andrea Mazzoleni
#ifndef SEARCH_H
#define SEARCH_H
#include "elem.h"
#include "state.h"
/****************************************************************************/
/* search */
/**
* Search file.
* File used to search for moved data.
*/
struct snapraid_search_file {
char* path; /**< Full path of the file. */
char* name; /**< Pointer of the name inside the path. */
data_off_t size;
int64_t mtime_sec;
int mtime_nsec;
/* nodes for data structures */
tommy_node node;
};
/**
* Deallocate a search file.
*/
void search_file_free(void* void_file);
/**
* Fetch a file from the size, timestamp and name.
* Return ==0 if the block is found, and copied into buffer.
*/
int state_search_fetch(struct snapraid_state* state, int prevhash, struct snapraid_file* missing_file, block_off_t missing_file_pos, struct snapraid_block* missing_block, unsigned char* buffer);
/**
* Import files from the specified directory.
*/
void state_search(struct snapraid_state* state, const char* dir);
/**
* Import files from all the data disks.
*/
void state_search_array(struct snapraid_state* state);
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,26 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
#ifndef SNAPRAID_H
#define SNAPRAID_H
/****************************************************************************/
/* snapraid */
void speed(int period, int disks_number, int blocks_size);
/**
* Runs the extensive test suite, including all unit tests and selftest.
*/
void test(int argc, char* argv[]);
/**
* Runs a fast self-test for functionality that could be miscompiled,
* primarily to verify inline assembly clobber and ABI requirements.
*/
void selftest(void);
int snapraid_main(int argc, char* argv[]);
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,142 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2013 Andrea Mazzoleni
/*
* Derivative work from SpookyV2.cpp/h
*
* WARNING!!!! Note that this implementation doesn't use the short hash optimization
* resulting in different hashes for any length shorter than 192 bytes
*
* SpookyHash
* http://burtleburtle.net/bob/hash/spooky.html
*
* Exact source used as reference:
* http://burtleburtle.net/bob/c/SpookyV2.h
* http://burtleburtle.net/bob/c/SpookyV2.cpp
*/
// Spooky Hash
// A 128-bit noncryptographic hash, for checksums and table lookup
// By Bob Jenkins. Public domain.
// Oct 31 2010: published framework, disclaimer ShortHash isn't right
// Nov 7 2010: disabled ShortHash
// Oct 31 2011: replace End, ShortMix, ShortEnd, enable ShortHash again
// April 10 2012: buffer overflow on platforms without unaligned reads
// July 12 2012: was passing out variables in final to in/out in short
// July 30 2012: I reintroduced the buffer overflow
// August 5 2012: SpookyV2: d = should be d += in short hash, and remove extra mix from long hash
//
// Up to 3 bytes/cycle for long messages. Reasonably fast for short messages.
// All 1 or 2 bit deltas achieve avalanche within 1% bias per output bit.
//
// This was developed for and tested on 64-bit x86-compatible processors.
// It assumes the processor is little-endian. There is a macro
// controlling whether unaligned reads are allowed (by default they are).
// This should be an equally good hash on big-endian machines, but it will
// compute different results on them than on little-endian machines.
//
// Google's CityHash has similar specs to SpookyHash, and CityHash is faster
// on new Intel boxes. MD4 and MD5 also have similar specs, but they are orders
// of magnitude slower. CRCs are two or more times slower, but unlike
// SpookyHash, they have nice math for combining the CRCs of pieces to form
// the CRCs of wholes. There are also cryptographic hashes, but those are even
// slower than MD5.
//
#define rd(data, x) util_read64((const uint8_t*)(data) + (x) * 8)
#define Mix(data, s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11) \
s0 += rd(data, 0); s2 ^= s10; s11 ^= s0; s0 = util_rotl64(s0, 11); s11 += s1; \
s1 += rd(data, 1); s3 ^= s11; s0 ^= s1; s1 = util_rotl64(s1, 32); s0 += s2; \
s2 += rd(data, 2); s4 ^= s0; s1 ^= s2; s2 = util_rotl64(s2, 43); s1 += s3; \
s3 += rd(data, 3); s5 ^= s1; s2 ^= s3; s3 = util_rotl64(s3, 31); s2 += s4; \
s4 += rd(data, 4); s6 ^= s2; s3 ^= s4; s4 = util_rotl64(s4, 17); s3 += s5; \
s5 += rd(data, 5); s7 ^= s3; s4 ^= s5; s5 = util_rotl64(s5, 28); s4 += s6; \
s6 += rd(data, 6); s8 ^= s4; s5 ^= s6; s6 = util_rotl64(s6, 39); s5 += s7; \
s7 += rd(data, 7); s9 ^= s5; s6 ^= s7; s7 = util_rotl64(s7, 57); s6 += s8; \
s8 += rd(data, 8); s10 ^= s6; s7 ^= s8; s8 = util_rotl64(s8, 55); s7 += s9; \
s9 += rd(data, 9); s11 ^= s7; s8 ^= s9; s9 = util_rotl64(s9, 54); s8 += s10; \
s10 += rd(data, 10); s0 ^= s8; s9 ^= s10; s10 = util_rotl64(s10, 22); s9 += s11; \
s11 += rd(data, 11); s1 ^= s9; s10 ^= s11; s11 = util_rotl64(s11, 46); s10 += s0;
#define EndPartial(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11) \
h11 += h1; h2 ^= h11; h1 = util_rotl64(h1, 44); \
h0 += h2; h3 ^= h0; h2 = util_rotl64(h2, 15); \
h1 += h3; h4 ^= h1; h3 = util_rotl64(h3, 34); \
h2 += h4; h5 ^= h2; h4 = util_rotl64(h4, 21); \
h3 += h5; h6 ^= h3; h5 = util_rotl64(h5, 38); \
h4 += h6; h7 ^= h4; h6 = util_rotl64(h6, 33); \
h5 += h7; h8 ^= h5; h7 = util_rotl64(h7, 10); \
h6 += h8; h9 ^= h6; h8 = util_rotl64(h8, 13); \
h7 += h9; h10 ^= h7; h9 = util_rotl64(h9, 38); \
h8 += h10; h11 ^= h8; h10 = util_rotl64(h10, 53); \
h9 += h11; h0 ^= h9; h11 = util_rotl64(h11, 42); \
h10 += h0; h1 ^= h10; h0 = util_rotl64(h0, 54);
#define End(data, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11) \
h0 += rd(data, 0); h1 += rd(data, 1); h2 += rd(data, 2); h3 += rd(data, 3); \
h4 += rd(data, 4); h5 += rd(data, 5); h6 += rd(data, 6); h7 += rd(data, 7); \
h8 += rd(data, 8); h9 += rd(data, 9); h10 += rd(data, 10); h11 += rd(data, 11); \
EndPartial(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); \
EndPartial(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11); \
EndPartial(h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11);
// number of uint64_t's in internal state
#define sc_numVars 12
// size of the internal state
#define sc_blockSize (sc_numVars * 8)
//
// sc_const: a constant which:
// * is not zero
// * is odd
// * is a not-very-regular mix of 1's and 0's
// * does not need any other special mathematical properties
//
#define sc_const 0xdeadbeefdeadbeefULL
static void SpookyHash128(const void* data, size_t size, const uint8_t* seed, uint8_t* digest)
{
uint64_t h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11;
uint8_t buf[sc_blockSize];
size_t nblocks;
const uint8_t* p;
const uint8_t* end;
size_t size_remainder;
h9 = util_read64(seed + 0);
h10 = util_read64(seed + 8);
h0 = h3 = h6 = h9;
h1 = h4 = h7 = h10;
h2 = h5 = h8 = h11 = sc_const;
nblocks = size / sc_blockSize;
p = data;
end = p + nblocks * sc_blockSize;
/* body */
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC unroll 1
#elif defined(__clang__)
#pragma unroll 1
#endif
while (p < end) {
Mix(p, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11);
p += sc_blockSize;
}
/* tail */
size_remainder = size - nblocks * sc_blockSize;
memcpy(buf, p, size_remainder);
memset(buf + size_remainder, 0, sc_blockSize - size_remainder);
buf[sc_blockSize - 1] = size_remainder;
/* finalization */
End(buf, h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11);
util_write64(digest + 0, h0);
util_write64(digest + 8, h1);
}

File diff suppressed because it is too large Load diff

View file

@ -1,520 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
#ifndef STATE_H
#define STATE_H
#include "elem.h"
struct snapraid_handle;
struct snapraid_io;
/****************************************************************************/
/* parity level */
/**
* Max level of parity supported.
*/
#define LEV_MAX 6
/**
* Return the parity name: Parity, 2-Parity, 3-Parity, 4-Parity, 5-Parity, 6-Parity.
*/
const char* lev_name(unsigned level);
/**
* Return the parity name used in the config file: parity, 2-parity, 3-parity, 4-parity, 5-parity, 6-parity.
*/
const char* lev_config_name(unsigned level);
/**
* Maximum byte length of a logical disk name.
*/
#define DISK_NAME_MAX 127
/**
* Validate a logical disk name.
*
* Returns 0 if valid, or a static string error reason if invalid.
*/
const char* disk_name_invalid_reason(const char* name);
/****************************************************************************/
/* state */
/**
* Units for disk space.
*/
#define KILO (1000)
#define MEGA (1000 * 1000)
#define GIGA (1000 * 1000 * 1000)
#define TERA (1000 * 1000 * 1000 * (uint64_t)1000)
#define KIBI (1024)
#define MEBI (1024 * 1024)
#define GIBI (1024 * 1024 * 1024)
#define TEBI (1024 * 1024 * 1024 * (uint64_t)1024)
#define SORT_DIR 1 /**< Sort by directory order. */
#define SORT_INODE 2 /**< Sort by inode. */
#define SORT_ALPHA 3 /**< Sort by alphabetic order. */
/**
* Options set only at startup.
* For all these options a value of 0 means nothing set, and to use the default.
*/
struct snapraid_option {
int gui; /**< GUI output. */
int gui_verbose; /**< GUI verbose output. */
int gui_rescan_after; /**< GUI force a rescan after the command. */
int gui_touch_before; /**< GUI force a touch before the command. */
unsigned gui_threshold_removes; /**< GUI abort sync if too many removed files */
unsigned gui_threshold_updates; /**< GUI abort sync if too many updated files */
int auditonly; /**< In check, checks only the hash and not the parity. */
int badfileonly; /**< In fix, fixes only files marked as bad. */
int badblockonly; /**< In fix, fixes only the blocks marked as bad. */
int syncedonly; /**< In fix, fixes only files that are synced. */
int prehash; /**< Enables the prehash mode for sync. */
unsigned io_error_limit; /**< Max number of input/output errors before aborting. */
int force_zero; /**< Forced dangerous operations of syncing files now with zero size. */
int force_empty; /**< Forced dangerous operations of syncing disks now empty. */
int force_uuid; /**< Forced dangerous operations of syncing disks with uuid changed. */
int force_device; /**< Forced dangerous operations of using disks with save device id. */
int force_nocopy; /**< Force dangerous operations of syncing files without using copy detection. */
int force_full; /**< Force a full parity update. */
int force_realloc; /**< Force a full reallocation and parity update. */
uint64_t parity_tail; /**< Limit the reallocation of the location at the specified parity tail */
int expect_unrecoverable; /**< Expect presence of unrecoverable error in checking or fixing. */
int expect_recoverable; /**< Expect presence of recoverable error in checking. */
int skip_device; /**< Skip devices matching checks. */
int skip_sign; /**< Skip the sign check for content files. */
int skip_fallocate; /**< Skip the use of fallocate(). */
int skip_space_holder; /**< Skip the use of spaceholder file. */
int file_mode; /**< File mode. Mask of ADVISE_* flags. */
int skip_lock; /**< Skip the lock file protection. */
int skip_self; /**< Skip the self-test. */
int skip_content_check; /**< Relax some content file checks. */
int skip_parity_access; /**< Skip the parity access for commands that don't need it. */
int skip_disk_access; /**< Skip the data disk access for commands that don't need it. */
int skip_content_access; /**< Skip the content access for commands that don't need it. */
int kill_after_sync; /**< Kill the process after sync without saving the final state. */
int kill_before_sync; /**< Kill the process before sync after saving the initial state. */
int kill_after_resize; /**< Kill the process after parity resize before the normal post-resize state write. */
int force_murmur3; /**< Force Murmur3 choice. */
int force_spooky2; /**< Force Spooky2 choice. */
int force_order; /**< Force sorting order. One of the SORT_* defines. */
unsigned force_scrub_at; /**< Force scrub for the specified number of blocks. */
int force_scrub_even; /**< Force scrub of all the even blocks. */
int force_content_write; /**< Force the update of the content file. */
int skip_content_write; /**< Skip the update of the content file. */
int force_scan_winfind; /**< Force the use of FindFirst/Next in Windows to list directories. */
int force_progress; /**< Force the use of the progress status. */
unsigned force_autosave_at; /**< Force autosave at the specified block. */
int fake_device; /**< Fake device data. */
int no_warnings; /**< Remove some warning messages. */
int expected_missing; /**< If missing files are expected and should not be reported. */
int fake_uuid; /**< Set fakes UUID for testing. */
int match_first_uuid; /**< Force the matching of the first UUID. */
int force_parity_update; /**< Force parity update even if data is not changed. */
unsigned io_cache; /**< Number of IO buffers to use. 0 for default. */
int force_stats; /**< Force stats print during process. */
uint64_t parity_limit_size; /**< Test limit for parity files. */
int skip_multi_scan; /**< Don't use threads in scan. */
uint64_t bwlimit; /**< Bandwidth limit in bytes per second. */
};
struct snapraid_state {
struct snapraid_option opt; /**< Setup options. */
int mapped_device; /**< Devices were already mapped */
int snapshot; /**< Enable snapshot support */
int filter_hidden; /**< Filter out hidden files. */
uint64_t autosave; /**< Autosave after the specified amount of data. 0 to disable. */
int need_write; /**< If the state is changed. */
int written; /**< If the state was written at least one time */
uint32_t block_size; /**< Block size in bytes. */
unsigned raid_mode; /**< Raid mode to use. RAID_MODE_DEFAULT or RAID_MODE_ALTERNATE. */
int file_mode; /**< File access mode. Combination of ADVISE_* flags. */
struct snapraid_parity parity[LEV_MAX]; /**< Parity vector. */
char share[PATH_MAX]; /**< Path of the share tree. If !=0 pool links are created in a different way. */
char pool[PATH_MAX]; /**< Path of the pool tree. */
uint64_t pool_device; /**< Device identifier of the pool. */
unsigned char hashseed[HASH_MAX]; /**< Hash seed. Just after a uint64 to provide a minimal alignment. */
unsigned char prevhashseed[HASH_MAX]; /**< Previous hash seed. In case of rehash. */
char lockfile[PATH_MAX]; /**< Path of the lock file to use. */
unsigned level; /**< Number of parity levels. 1 for PAR1, 2 for PAR2. */
unsigned hash; /**< Hash kind used. */
unsigned prevhash; /**< Previous hash kind used. In case of rehash. */
unsigned besthash; /**< Best hash suggested. */
const char* command; /**< Command running. */
struct smartignore_struct smartignore[SMART_IGNORE_MAX]; /**< Smart attributes to ignore for all devices. */
uint64_t rehash_blocks; /**< Blocks marked rehash */
uint64_t bad_blocks; /**< Blocks marked bad */
uint64_t unsynced_blocks; /**< If the parity is invalid, and a sync is needed. */
uint64_t unscrubbed_blocks; /**< Blocks never scrubbed */
uint64_t removed_files; /**< Files removed. Updated in scan */
uint64_t updated_files; /**< Files updated. Updated in scan */
tommy_list contentlist; /**< List of content files. */
tommy_list disklist; /**< List of all the data disks. */
tommy_list extralist; /**< List of all the other disks. */
tommy_list maplist; /**< List of all the disk mappings. */
tommy_list filterlist; /**< List of inclusion/exclusion. */
tommy_list importlist; /**< List of import file. */
tommy_hashdyn importset; /**< Hashtable by hash of all the import blocks. */
tommy_hashdyn previmportset; /**< Hashtable by prevhash of all the import blocks. Valid only if we are in a rehash state. */
tommy_hashdyn searchset; /**< Hashtable by timestamp of all the search files. */
tommy_arrayblkof infoarr; /**< Block information array. */
tommy_list bucketlist; /**< Sorted list of info bucket. Derived from infoarr, but updated only state_read()/state_write() */
block_off_t bucketcount; /**< Sum of all the counts of the list */
/* thermal */
tommy_list thermallist; /**< List of all thermal state */
int thermal_stop_gathering; /**< If thermal data gathering is stopped */
int thermal_system_temperature; /**< System temperature. 0 if not available */
int thermal_ambient_temperature; /**< Ambient temperature used as thermal model reference. 0 if not available */
int thermal_highest_temperature; /**< Current highest temperature */
uint64_t thermal_first; /**< Monotonic time of the first measure */
uint64_t thermal_latest; /**< Monotonic time of latest measure */
int thermal_cooldown_time; /**< Cooldown wait time in seconds */
int thermal_temperature_limit; /**< Upper limit temperature of the operating range */
/**
* Cumulative time used for computations.
*/
uint64_t tick_misc;
uint64_t tick_sched;
uint64_t tick_raid;
uint64_t tick_hash;
/**
* Cumulative time used for all io operations of disks.
*/
uint64_t tick_io;
/**
* Last time used for time measure.
*/
uint64_t tick_last;
time_t progress_whole_start; /**< Initial start of the whole process. */
time_t progress_interruption; /**< Time of the start of the progress interruption. */
time_t progress_wasted; /**< Time wasted in interruptions. */
time_t progress_time[PROGRESS_MAX]; /**< Last times of progress. */
block_off_t progress_pos[PROGRESS_MAX]; /**< Last positions of progress. */
data_off_t progress_size[PROGRESS_MAX]; /**< Last sizes of progress. */
uint64_t progress_tick_misc[PROGRESS_MAX]; /**< Last cpu ticks of progress. */
uint64_t progress_tick_sched[PROGRESS_MAX]; /**< Last scheduling ticks of progress. */
uint64_t progress_tick_raid[PROGRESS_MAX]; /**< Last raid ticks of progress. */
uint64_t progress_tick_hash[PROGRESS_MAX]; /**< Last hash ticks of progress. */
uint64_t progress_tick_io[PROGRESS_MAX]; /**< Last io ticks of progress. */
int progress_ptr; /**< Pointer to the next position to fill. Rolling over. */
int progress_tick; /**< Number of measures done. */
int no_conf; /**< Automatically add missing info. Used to load content without a configuration file. */
};
/**
* Initialize the state.
*/
void state_init(struct snapraid_state* state);
/**
* Deinitialize the state.
*/
void state_done(struct snapraid_state* state);
/**
* Read the configuration file.
*/
void state_config(struct snapraid_state* state, const char* path, const char* command, struct snapraid_option* opt, tommy_list* filterlist_disk);
/**
* Probe the state.
*/
void state_probe(struct snapraid_state* state);
/**
* Read the state.
*/
void state_read(struct snapraid_state* state);
/**
* Check if all configured parity splits have persistent sizes.
*/
int state_is_write_ready(struct snapraid_state* state);
/**
* Require initialized parity split sizes before commands that can save content.
*/
void state_require_write_ready(struct snapraid_state* state);
/**
* Count the number of unsynced parity positions using an event sweep across extents.
* Counts positions in [blockmin, blockmax). The caller must ensure that the disk list,
* extent trees, and block states remain unchanged for the duration of the call.
*/
uint64_t fs_count_unsynced(struct snapraid_state* state, block_off_t blockmin, block_off_t blockmax);
/**
* Write the new state.
*/
void state_write(struct snapraid_state* state);
/**
* Signal that we reached a stable state with all parity computed.
*/
void state_commit(struct snapraid_state* state);
/**
* Diff all the disks.
*/
int state_diff(struct snapraid_state* state);
/**
* Scan all the disks to update the state.
*/
void state_scan(struct snapraid_state* state);
/**
* Set the nanosecond timestamp of all files that have a zero value.
*/
int state_touch(struct snapraid_state* state);
/**
* Map devices if not already done.
*/
void state_devmap(struct snapraid_state* state);
/**
* Devices operations.
*/
int state_device(struct snapraid_state* state, int operation, tommy_list* filterlist_disk);
/**
* Perform a device operation, continuing after a failed flush when force is set.
*/
int state_device_force(struct snapraid_state* state, int operation, tommy_list* filterlist_disk, int force);
/**
* Sync the parity data.
*/
int state_sync(struct snapraid_state* state, block_off_t blockstart, block_off_t blockcount);
/**
* Check (and fixes) all the files and parity data.
* \param fix If we have to fix, after checking.
*/
int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, block_off_t blockcount);
/**
* Dry the files.
*/
int state_dry(struct snapraid_state* state, block_off_t blockstart, block_off_t blockcount);
/**
* Rehash the files.
*/
void state_rehash(struct snapraid_state* state);
/**
* Scrub levels.
*/
#define SCRUB_AUTO -1 /**< Automatic selection. */
#define SCRUB_BAD -2 /**< Scrub only the bad blocks. */
#define SCRUB_NEW -3 /**< Scrub the new blocks. */
#define SCRUB_FULL -4 /**< Scrub everything. */
#define SCRUB_EVEN -5 /**< Even blocks. */
/**
* Scrub the files.
*/
int state_scrub(struct snapraid_state* state, int plan, int olderthan);
/**
* Print the status.
*/
int state_status(struct snapraid_state* state);
/**
* Find duplicates.
*/
void state_dup(struct snapraid_state* state);
/**
* List content.
*/
void state_list(struct snapraid_state* state);
/**
* Create pool tree.
*/
void state_pool(struct snapraid_state* state);
/**
* Refresh the free space info.
*
* Note that it requires disks access.
*/
void state_refresh(struct snapraid_state* state);
/**
* Skip files, symlinks and dirs.
* Apply any skip access disk.
*/
void state_skip(struct snapraid_state* state);
/**
* Filter files, symlinks and dirs.
* Apply an additional filter to the list currently loaded.
*/
void state_filter(struct snapraid_state* state, tommy_list* filterlist_file, tommy_list* filterlist_disk, int filter_missing, int filter_error);
/**
* Begin the progress visualization.
*/
int state_progress_begin(struct snapraid_state* state, block_off_t blockstart, block_off_t blockmax, block_off_t countmax);
/**
* End the progress visualization.
*/
void state_progress_end(struct snapraid_state* state, block_off_t countpos, block_off_t countmax, data_off_t countsize, const char* msg);
/**
* Write the progress.
*/
int state_progress(struct snapraid_state* state, struct snapraid_io* io, block_off_t blockpos, block_off_t countpos, block_off_t countmax, data_off_t countsize);
/**
* Stop temporarily the progress.
*/
void state_progress_stop(struct snapraid_state* state);
/**
* Restart the progress.
*/
void state_progress_restart(struct snapraid_state* state);
/**
* Set the usage time as wasted one not counted.
*/
void state_usage_waste(struct snapraid_state* state);
/**
* Set the usage time for CPU.
*/
void state_usage_misc(struct snapraid_state* state);
void state_usage_sched(struct snapraid_state* state);
void state_usage_raid(struct snapraid_state* state);
void state_usage_hash(struct snapraid_state* state);
/**
* Set the last file used
*/
void state_usage_file(struct snapraid_state* state, struct snapraid_disk* disk, struct snapraid_file* file);
/**
* Set the usage time for a set of data disks.
*/
void state_usage_disk(struct snapraid_state* state, struct snapraid_handle* handle_map, unsigned* waiting_map, unsigned waiting_mac);
/**
* Set the usage time for a set of parity disk.
*/
void state_usage_parity(struct snapraid_state* state, unsigned* waiting_map, unsigned waiting_mac);
/**
* Print the stats of the usage time.
*/
void state_usage_print(struct snapraid_state* state);
/**
* Check the file-system on all disks.
* On error it aborts.
*/
void state_fscheck(struct snapraid_state* state, const char* ope);
/**
* Measure the temperature of all disks.
* Return 0 if thermal information was successfully gathered, -1 if thermal gathering failed, is not supported, or no valid temperature is available.
* Individual disks without a valid temperature are ignored as long as at least one disk provides a valid temperature.
*/
int state_thermal(struct snapraid_state* state, time_t now);
/**
* Check if the temperature is outside the operating range
*/
int state_thermal_alarm(struct snapraid_state* state);
/**
* Cool down the system
*/
void state_thermal_cooldown(struct snapraid_state* state);
/**
* Start of thermal processing
*/
int state_thermal_begin(struct snapraid_state* state, time_t now);
/**
* Load the ignore file .snapraidignore
*/
int state_load_ignore_file(tommy_list* filter_list, const char* path, const char* sub);
/**
* Report attributes into the log
*/
void state_attr(struct snapraid_state* state, tommy_list* low);
/**
* Create (or reuse existing) scan snapshots
*/
int state_snapshot_scan(struct snapraid_state* state);
/**
* Promote scan snapshots to pending before starting parity processing.
*/
int state_snapshot_pending(struct snapraid_state* state);
/**
* Make the pending snapshots as stable
*/
int state_snapshot_commit(struct snapraid_state* state);
/**
* Use the snapshots for reading only commands
*/
void state_snapshot_read(struct snapraid_state* state);
/**
* Use the snapshots for the reading part (filtered out disks) of writing commands
*/
void state_snapshot_write(struct snapraid_state* state, tommy_list* filterlist_disk);
/**
* Cleanup snapshots
*
* Required only in Windows.
*/
void state_snapshot_cleanup(struct snapraid_state* state);
/****************************************************************************/
/* misc */
/**
* Generate a dummy configuration file from a content file.
*/
void generate_configuration(const char* content);
/**
* Parse smartctl command.
*/
int parse_smartctl(const char* custom, char* smartctl, size_t smartctl_size, char* smartctl_info, size_t smartctl_info_size);
/**
* Apply smart ignore logic to devinfo.
*/
void state_smart_ignore(struct snapraid_state* state, devinfo_t* devinfo);
#endif

View file

@ -1,489 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2013 Andrea Mazzoleni
#include "os/portable.h"
#include "support.h"
#include "elem.h"
#include "state.h"
#include "parity.h"
#include "handle.h"
#include "raid/raid.h"
/****************************************************************************/
/* status */
unsigned day_ago(time_t ref, time_t now)
{
/* in case some dates is in the future */
if (now < ref)
return 0;
now -= ref;
return (unsigned)(now / (24 * 3600));
}
#define GRAPH_COLUMN 70
#define GRAPH_ROW 15
/**
* Bit used to mark unscrubbed time info.
*/
#define TIME_NEW 1
int state_status(struct snapraid_state* state)
{
block_off_t blockmax;
block_off_t i;
time_t now;
block_off_t count;
unsigned l;
unsigned dayoldest, daymedian, daynewest;
block_off_t bar_scrubbed[GRAPH_COLUMN];
block_off_t bar_new[GRAPH_COLUMN];
block_off_t barmax;
time_t oldest, newest, median;
unsigned x, y;
tommy_node* node_disk;
unsigned file_count;
unsigned file_fragmented;
unsigned extra_fragment;
unsigned file_zerosubsecond;
uint64_t file_size;
uint64_t file_block_count;
uint64_t file_block_free;
unsigned dealloc_count;
block_off_t parity_block_free;
uint64_t all_wasted;
int free_not_zero;
/* get the present time */
now = time(0);
/* keep track if at least a free info is available */
free_not_zero = 0;
blockmax = parity_allocated_size(state);
log_tag("summary:block_size:%u\n", state->block_size);
log_tag("summary:parity_block_count:%" PRIu64 "\n", blockmax);
/* get the minimum parity free space */
parity_block_free = state->parity[0].free_blocks;
for (l = 0; l < state->level; ++l) {
log_tag("summary:parity_block_total:%s:%" PRIu64 "\n", lev_config_name(l), state->parity[l].total_blocks);
log_tag("summary:parity_block_free:%s:%" PRIu64 "\n", lev_config_name(l), state->parity[l].free_blocks);
if (state->parity[l].free_blocks < parity_block_free)
parity_block_free = state->parity[l].free_blocks;
if (state->parity[l].free_blocks != 0)
free_not_zero = 1;
}
log_tag("summary:parity_block_free_min:%" PRIu64 "\n", parity_block_free);
printf("SnapRAID status report:\n");
printf("\n");
printf(" Files Fragmented Excess Wasted Used Free Use Name\n");
printf(" Files Fragments GB GB GB\n");
/* count fragments */
dealloc_count = 0;
file_count = 0;
file_size = 0;
file_block_count = 0;
file_block_free = 0;
file_fragmented = 0;
extra_fragment = 0;
file_zerosubsecond = 0;
all_wasted = 0;
for (node_disk = state->disklist; node_disk != 0; node_disk = node_disk->next) {
struct snapraid_disk* disk = node_disk->data;
tommy_node* node;
block_off_t j;
unsigned disk_file_count = 0;
unsigned disk_file_fragmented = 0;
unsigned disk_extra_fragment = 0;
unsigned disk_file_zerosubsecond = 0;
block_off_t disk_block_count = 0;
uint64_t disk_file_size = 0;
block_off_t disk_block_latest_used = 0;
block_off_t disk_block_max_by_space;
block_off_t disk_block_max_by_parity;
block_off_t disk_block_max;
uint64_t disk_used_bytes;
uint64_t disk_free_bytes;
int64_t wasted;
dealloc_count += tommy_list_count(&disk->dealloclist);
/* for each file in the disk */
node = disk->filelist;
while (node) {
struct snapraid_file* file;
file = node->data;
node = node->next; /* next node */
if (file->mtime_nsec == STAT_NSEC_INVALID
|| file->mtime_nsec == 0
) {
++file_zerosubsecond;
++disk_file_zerosubsecond;
if (disk_file_zerosubsecond < 50)
log_tag("zerosubsecond:%s:%s: \n", disk->name, esc_tag(file->sub));
if (disk_file_zerosubsecond == 50)
log_tag("zerosubsecond:%s:%s: (more follow)\n", disk->name, esc_tag(file->sub));
}
/* check fragmentation */
if (file->blockmax != 0) {
block_off_t prev_pos;
block_off_t last_pos;
int fragmented;
fragmented = 0;
prev_pos = fs_file2par_get(disk, file, 0);
for (j = 1; j < file->blockmax; ++j) {
block_off_t parity_pos = fs_file2par_get(disk, file, j);
if (prev_pos + 1 != parity_pos) {
fragmented = 1;
++extra_fragment;
++disk_extra_fragment;
}
prev_pos = parity_pos;
}
/* keep track of latest block used */
last_pos = fs_file2par_get(disk, file, file->blockmax - 1);
if (last_pos > disk_block_latest_used) {
disk_block_latest_used = last_pos;
}
if (fragmented) {
++file_fragmented;
++disk_file_fragmented;
}
disk_block_count += file->blockmax;
}
/* count files */
++file_count;
++disk_file_count;
file_size += file->size;
file_block_count += file->blockmax;
disk_file_size += file->size;
}
if (disk->free_blocks != 0)
free_not_zero = 1;
/* get the free block info */
disk_block_max_by_space = disk_block_count + disk->free_blocks;
disk_block_max_by_parity = blockmax + parity_block_free;
/*
* The maximum usable space in a disk is limited by the smallest
* of the disk size and the parity size
* the wasted space is the space that we have to leave
* free on the data disk, when the parity is filled up
*/
if (disk_block_max_by_space < disk_block_max_by_parity) {
disk_block_max = disk_block_max_by_space;
} else {
disk_block_max = disk_block_max_by_parity;
}
/*
* Wasted space is the difference of the two maximum size
* if negative, it's extra space available in parity
*/
wasted = (int64_t)disk_block_max_by_space - (int64_t)disk_block_max_by_parity;
wasted *= state->block_size;
if (wasted > 0)
all_wasted += wasted;
file_block_free += disk_block_max - disk_block_count;
printf("%8u", disk_file_count);
printf("%8u", disk_file_fragmented);
printf("%8u", disk_extra_fragment);
if (wasted < -100LL * GIGA) {
printf(" -");
} else {
printf("%8.1f", (double)wasted / GIGA);
}
printf("%8" PRIu64, disk_file_size / GIGA);
if (disk_block_max == 0 && disk_block_count == 0) {
/* if the disk is empty and we don't have the free space info */
printf(" -");
printf(" - ");
} else {
printf("%8" PRIu64, (disk_block_max - disk_block_count) * (uint64_t)state->block_size / GIGA);
printf(" %3u%%", muldiv(disk_block_count, 100, disk_block_max));
}
printf(" %s\n", disk->name);
log_tag("summary:disk_file_count:%s:%u\n", disk->name, disk_file_count);
log_tag("summary:disk_block_count:%s:%" PRIu64 "\n", disk->name, disk_block_count);
log_tag("summary:disk_fragmented_file_count:%s:%u\n", disk->name, disk_file_fragmented);
log_tag("summary:disk_excess_fragment_count:%s:%u\n", disk->name, disk_extra_fragment);
log_tag("summary:disk_zerosubsecond_file_count:%s:%u\n", disk->name, disk_file_zerosubsecond);
log_tag("summary:disk_file_size:%s:%" PRIu64 "\n", disk->name, disk_file_size);
log_tag("summary:disk_block_allocated:%s:%" PRIu64 "\n", disk->name, disk_block_latest_used + 1);
log_tag("summary:disk_block_total:%s:%" PRIu64 "\n", disk->name, disk->total_blocks);
log_tag("summary:disk_block_free:%s:%" PRIu64 "\n", disk->name, disk->free_blocks);
log_tag("summary:disk_block_max_by_space:%s:%" PRIu64 "\n", disk->name, disk_block_max_by_space);
log_tag("summary:disk_block_max_by_parity:%s:%" PRIu64 "\n", disk->name, disk_block_max_by_parity);
log_tag("summary:disk_block_max:%s:%" PRIu64 "\n", disk->name, disk_block_max);
log_tag("summary:disk_space_wasted:%s:%" PRId64 "\n", disk->name, wasted);
disk_used_bytes = disk_block_count * (uint64_t)state->block_size;
disk_free_bytes = (disk_block_max - disk_block_count) * (uint64_t)state->block_size;
log_tag("summary:disk_used:%s:%" PRIu64 "\n", disk->name, disk_used_bytes);
log_tag("summary:disk_free:%s:%" PRIu64 "\n", disk->name, disk_free_bytes);
log_tag("summary:disk_use_percent:%s:%u\n", disk->name, muldiv(disk_block_count, 100, disk_block_max));
}
/* totals */
printf(" --------------------------------------------------------------------------\n");
printf("%8u", file_count);
printf("%8u", file_fragmented);
printf("%8u", extra_fragment);
printf("%8.1f", (double)all_wasted / GIGA);
printf("%8" PRIu64, file_size / GIGA);
printf("%8" PRIu64, file_block_free * state->block_size / GIGA);
printf(" %3u%%", muldiv(file_block_count, 100, file_block_count + file_block_free));
printf("\n");
/* warn about invalid data free info */
if (!free_not_zero)
printf("\nWARNING! Free space info will be valid after the first sync.\n");
log_tag("summary:file_count:%u\n", file_count);
log_tag("summary:file_block_count:%" PRIu64 "\n", file_block_count);
log_tag("summary:fragmented_file_count:%u\n", file_fragmented);
log_tag("summary:excess_fragment_count:%u\n", extra_fragment);
log_tag("summary:zerosubsecond_file_count:%u\n", file_zerosubsecond);
log_tag("summary:file_size:%" PRIu64 "\n", file_size);
log_tag("summary:parity_size:%" PRIu64 "\n", blockmax * (uint64_t)state->block_size);
log_tag("summary:parity_size_max:%" PRIu64 "\n", (blockmax + parity_block_free) * (uint64_t)state->block_size);
log_tag("summary:hash:%s\n", hash_config_name(state->hash));
log_tag("summary:prev_hash:%s\n", hash_config_name(state->prevhash));
log_tag("summary:best_hash:%s\n", hash_config_name(state->besthash));
log_tag("summary:total_wasted:%" PRIu64 "\n", all_wasted);
log_tag("summary:total_used:%" PRIu64 "\n", file_size);
log_tag("summary:total_free:%" PRIu64 "\n", file_block_free * state->block_size);
log_tag("summary:total_use_percent:%u\n", muldiv(file_block_count, 100, file_block_count + file_block_free));
log_flush();
oldest = 0;
median = 0;
newest = 0;
count = 0;
for (tommy_node* j = tommy_list_head(&state->bucketlist); j != 0; j = j->next) {
struct snapraid_bucket* bucket = j->data;
block_off_t bucket_count = bucket->count_scrubbed + bucket->count_justsynced;
if (count == 0)
oldest = bucket->time_at;
if (count < state->bucketcount / 2)
median = bucket->time_at;
newest = bucket->time_at;
count += bucket_count;
}
if (!count) {
printf("The array is empty.\n");
return 0;
}
dayoldest = day_ago(oldest, now);
daymedian = day_ago(median, now);
daynewest = day_ago(newest, now);
log_tag("summary:scrub_oldest_days:%u\n", dayoldest);
log_tag("summary:scrub_median_days:%u\n", daymedian);
log_tag("summary:scrub_newest_days:%u\n", daynewest);
/* compute graph limits */
barmax = 0;
memset(bar_scrubbed, 0, sizeof(bar_scrubbed));
memset(bar_new, 0, sizeof(bar_new));
for (tommy_node* j = tommy_list_head(&state->bucketlist); j != 0; j = j->next) {
struct snapraid_bucket* bucket = j->data;
unsigned column = muldiv(bucket->time_at - oldest, GRAPH_COLUMN, newest - oldest + 1);
bar_scrubbed[column] += bucket->count_scrubbed;
bar_new[column] += bucket->count_justsynced;
if (bar_scrubbed[column] + bar_new[column] > barmax)
barmax = bar_scrubbed[column] + bar_new[column];
}
/* output scrub history as structured data */
log_tag("scrub_graph_range:%u:%" PRIu64 "\n", GRAPH_COLUMN, barmax);
for (l = 0; l < GRAPH_COLUMN; ++l) {
unsigned days_ago = dayoldest - (dayoldest - daynewest) * l / (GRAPH_COLUMN - 1);
log_tag("scrub_graph_bar:%u:%u:%" PRIu64 ":%" PRIu64 "\n", l, days_ago, bar_scrubbed[l], bar_new[l]);
}
printf("\n\n");
/* print the graph */
for (y = 0; y < GRAPH_ROW; ++y) {
if (y == 0)
printf("%3" PRIu64 "%%|", barmax * 100 / count);
else if (y == GRAPH_ROW - 1)
printf(" 0%%|");
else if (y == GRAPH_ROW / 2)
printf("%3" PRIu64 "%%|", barmax * 50 / count);
else
printf(" |");
for (x = 0; x < GRAPH_COLUMN; ++x) {
block_off_t pivot_upper = barmax * (GRAPH_ROW - y) / GRAPH_ROW;
block_off_t pivot_lower = barmax * (GRAPH_ROW - 1 - y) / GRAPH_ROW;
block_off_t both = bar_scrubbed[x] + bar_new[x];
block_off_t scrubbed = bar_scrubbed[x];
if (both > pivot_upper) {
if (scrubbed > pivot_lower)
printf("*");
else
printf("o");
} else if (both > pivot_lower) {
if (scrubbed == both)
printf("*");
else
printf("o");
} else {
if (y == GRAPH_ROW - 1)
printf("_");
else
printf(" ");
}
}
printf("\n");
}
printf(" %3u days ago of the last scrub/sync %3u\n", dayoldest, daynewest);
printf("\n");
printf("The oldest block was scrubbed %u days ago, the median %u, the newest %u.\n", dayoldest, daymedian, daynewest);
printf("\n");
if (newest > now) {
printf("WARNING! You have scrub dates in the future! The next sync/scrub will truncate them!\n");
}
if (state->unsynced_blocks) {
printf("WARNING! The array is NOT fully synced.\n");
printf("You have a sync in progress at %u%%.\n", muldiv(blockmax - state->unsynced_blocks, 100, blockmax));
if (dealloc_count) {
printf("WARNING! There are %u files updated or deleted from the array that may reduce the recovery probability until the next sync.\n", dealloc_count);
for (node_disk = state->disklist; node_disk != 0; node_disk = node_disk->next) {
struct snapraid_disk* disk = node_disk->data;
for (tommy_node* node = tommy_list_head(&disk->dealloclist); node != 0; node = node->next) {
struct snapraid_dealloc* dealloc = node->data;
msg_verbose("\t%s\n", fmt_term(disk, dealloc->sub));
}
}
}
} else {
printf("No sync is in progress.\n");
}
if (state->unscrubbed_blocks) {
printf("%u%% of the array is not scrubbed.\n", muldiv_upper(state->unscrubbed_blocks, 100, blockmax));
} else {
printf("The full array was scrubbed at least one time.\n");
}
if (file_zerosubsecond) {
printf("You have %u files with a zero sub-second timestamp.\n", file_zerosubsecond);
printf("Run 'snapraid touch' to set their sub-second timestamps to a non-zero value.\n");
} else {
printf("No file has a zero sub-second timestamp.\n");
}
if (state->rehash_blocks) {
printf("You have a rehash in progress at %u%%.\n", muldiv(count - state->rehash_blocks, 100, count));
} else {
if (state->besthash != state->hash) {
printf("No rehash is in progress, but for optimal performance one is recommended.\n");
} else {
printf("No rehash is in progress or needed.\n");
}
}
if (state->bad_blocks) {
printf("DANGER! In the array there are %" PRIu64 " errors!\n\n", state->bad_blocks);
block_off_t bad_range;
block_off_t bad_count;
block_off_t range_start;
block_off_t range_count;
printf("They are at blocks:");
/* print some of the errors */
bad_range = 0;
bad_count = 0;
range_start = 0;
range_count = 0;
for (i = 0; i <= blockmax; ++i) { /* one extra iteration to print the final range */
snapraid_info info = 0;
int is_bad = 0;
if (i < blockmax) {
info = info_get(&state->infoarr, i);
if (info != 0) /* unused blocks are never bad */
is_bad = info_get_bad(info);
}
if (is_bad) {
/* create or extend the range */
if (!range_count)
range_start = i;
++range_count;
} else {
/* break the range */
if (range_count) {
if (range_count == 1) {
printf(" %" PRIu64 "", range_start);
} else {
printf(" %" PRIu64 "-%" PRIu64 "", range_start, range_start + range_count - 1);
}
bad_count += range_count;
++bad_range;
range_count = 0;
}
}
if (bad_range > 100) {
printf(" and %" PRIu64 " more...", state->bad_blocks - bad_count);
break;
}
}
printf("\n");
printf("To fix them use the command 'snapraid -e fix'.\n");
printf("The errors will disappear from the 'status' at the next 'scrub' command.\n");
} else {
printf("No error detected.\n");
}
if (state->bad_blocks)
log_tag("summary:exit:bad\n");
else if (state->unsynced_blocks != 0)
log_tag("summary:exit:unsynced\n");
else
log_tag("summary:exit:ok\n");
return 0;
}

View file

@ -1,628 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2025 Andrea Mazzoleni
#include "os/portable.h"
#include "str.h"
#include "support.h"
/****************************************************************************/
/* string */
char* strpolish(char* s)
{
char* i = s;
while (*i) {
if (isspace((unsigned char)*i) || !isprint((unsigned char)*i))
*i = ' ';
++i;
}
return s;
}
unsigned strsplit(char** split_map, unsigned split_max, char* str, const char* delimiters, const char* trim, int trim_empty)
{
unsigned mac = 0;
if (*str == 0)
return 0;
while (mac < split_max) {
char* begin = str;
str += strcspn(str, delimiters);
char* end = str;
int has_next = *str != 0;
if (has_next) {
*str = 0;
++str;
}
if (trim != 0) {
begin += strspn(begin, trim);
while (end > begin && strchr(trim, end[-1]) != 0) {
--end;
*end = 0;
}
}
if (!trim_empty || *begin != 0) {
split_map[mac] = begin;
++mac;
}
if (!has_next)
break;
}
return mac;
}
unsigned argsplit(const char** split_map, unsigned split_max, char* str)
{
unsigned mac = 0;
/* skip leading whitespace */
while (*str != 0 && isspace((unsigned char)*str))
++str;
while (*str != 0 && mac < split_max) {
char* dst = str;
split_map[mac++] = dst;
#ifdef _WIN32
/*
* cmd.exe rules:
* Unquoted: '^' escapes next char; '"' opens a quoted block.
* Quoted: '"' closes the block; '^' is an ordinary character.
*/
int quoted = 0;
while (*str != 0 && (quoted || !isspace((unsigned char)*str))) {
if (quoted) {
if (*str == '"') {
quoted = 0;
++str;
} else {
*dst++ = *str++;
}
} else {
if (*str == '^' && *(str + 1) != 0) {
++str;
*dst++ = *str++;
} else if (*str == '"') {
quoted = 1;
++str;
} else {
*dst++ = *str++;
}
}
}
#else
/*
* bash rules:
* Single-quoted block: everything literal, no exceptions.
* Double-quoted block: '\' only escapes $, `, ", '\', newline;
* other backslashes are copied verbatim.
* Unquoted '\': always escapes the immediately following char.
*/
/* set of characters that '\' can escape inside double quotes */
static const char dq_escapable[] = "$`\"\\\n";
while (*str != 0 && !isspace((unsigned char)*str)) {
if (*str == '\'') {
/* single-quoted block: truly everything is literal */
++str;
while (*str != 0 && *str != '\'')
*dst++ = *str++;
if (*str == '\'')
++str;
} else if (*str == '"') {
/* double-quoted block */
++str;
while (*str != 0 && *str != '"') {
if (*str == '\\' && *(str + 1) != 0 && strchr(dq_escapable, *(str + 1))) {
++str;
}
*dst++ = *str++;
}
if (*str == '"')
++str;
} else if (*str == '\\') {
/* unquoted backslash: next character always literal */
++str;
if (*str != 0)
*dst++ = *str++;
} else {
*dst++ = *str++;
}
}
#endif
if (*str != 0)
++str; /* step past the delimiter */
/* skip whitespace before the next token */
while (*str != 0 && isspace((unsigned char)*str))
++str;
/* null-terminate after str has already moved on */
*dst = 0;
}
return mac;
}
char* strtrim(char* str)
{
char* begin;
char* end;
begin = str;
while (begin[0] && isspace((unsigned char)begin[0]))
++begin;
end = begin + strlen(begin);
while (end > begin && isspace((unsigned char)end[-1]))
--end;
end[0] = 0;
if (begin != str)
memmove(str, begin, end - begin + 1);
return str;
}
char* strlwr(char* str)
{
char* s = str;
while (*s) {
*s = tolower((unsigned char)*s);
++s;
}
return str;
}
char* worddigitstr(const char* haystack, const char* needle)
{
size_t len = strlen(needle);
const char* s;
if (len == 0)
return NULL;
for (s = haystack; (s = strstr(s, needle)) != NULL; ++s) {
/* left boundary */
if (s == haystack || isspace((unsigned char)s[-1]) || isdigit((unsigned char)s[-1])) {
/* right boundary */
if (s[len] == 0 || isspace((unsigned char)s[len]) || isdigit((unsigned char)s[len])) {
return (char*)s;
}
}
}
return NULL;
}
int strtoi(const char* nptr, char** endptr, int base)
{
long val;
int save_errno = errno;
errno = 0;
val = strtol(nptr, endptr, base);
if (errno == ERANGE) {
return val > 0 ? INT_MAX : INT_MIN;
}
if (val > INT_MAX) {
errno = ERANGE;
return INT_MAX;
}
if (val < INT_MIN) {
errno = ERANGE;
return INT_MIN;
}
if (errno == 0) {
errno = save_errno;
}
return (int)val;
}
unsigned strtou(const char* nptr, char** endptr, int base)
{
const char* p = nptr;
char* end;
unsigned long val;
int neg = 0;
int save_errno = errno;
while (isspace((unsigned char)*p)) {
++p;
}
if (*p == '-') {
neg = 1;
++p;
} else if (*p == '+') {
++p;
}
errno = 0;
val = strtoul(p, &end, base);
if (end == p) {
/* no conversion was performed */
if (endptr) {
*endptr = (char*)nptr;
}
errno = save_errno;
return 0;
}
if (endptr) {
*endptr = end;
}
if (errno == ERANGE || val > UINT_MAX) {
errno = ERANGE;
return UINT_MAX;
}
if (errno == 0) {
errno = save_errno;
}
if (neg) {
return (unsigned)-val;
}
return (unsigned)val;
}
unsigned strton(const char* nptr, char** endptr, int base)
{
const char* p = nptr;
unsigned val;
int save_errno = errno;
while (isspace((unsigned char)*p)) {
++p;
}
if (*p == '-') {
if (endptr) {
*endptr = (char*)nptr;
}
errno = ERANGE;
return (unsigned)-1;
}
errno = 0;
val = strtou(nptr, endptr, base);
if (errno == ERANGE) {
if (endptr) {
*endptr = (char*)nptr;
}
return (unsigned)-1;
}
if (errno == 0) {
errno = save_errno;
}
return val;
}
unsigned long strtonl(const char* nptr, char** endptr, int base)
{
const char* p = nptr;
unsigned long val;
int save_errno = errno;
while (isspace((unsigned char)*p)) {
++p;
}
if (*p == '-') {
if (endptr) {
*endptr = (char*)nptr;
}
errno = ERANGE;
return (unsigned long)-1;
}
errno = 0;
val = strtoul(nptr, endptr, base);
if (errno == ERANGE) {
if (endptr) {
*endptr = (char*)nptr;
}
return (unsigned long)-1;
}
if (errno == 0) {
errno = save_errno;
}
return val;
}
unsigned long long strtonll(const char* nptr, char** endptr, int base)
{
const char* p = nptr;
unsigned long long val;
int save_errno = errno;
while (isspace((unsigned char)*p)) {
++p;
}
if (*p == '-') {
if (endptr) {
*endptr = (char*)nptr;
}
errno = ERANGE;
return (unsigned long long)-1;
}
errno = 0;
val = strtoull(nptr, endptr, base);
if (errno == ERANGE) {
if (endptr) {
*endptr = (char*)nptr;
}
return (unsigned long long)-1;
}
if (errno == 0) {
errno = save_errno;
}
return val;
}
/****************************************************************************/
/* wnmatch */
/**
* Helper function for case-insensitive character comparison
*/
static inline int char_match(char p, char t)
{
#ifdef WIN32
return tolower((unsigned char)p) == tolower((unsigned char)t);
#else
return p == t;
#endif
}
/**
* Match character class [...]
* Return 0 if NOT matched
*/
static const char* match_class(const char* p, char t)
{
int negate = 0;
int matched = 0;
if (*p == '!' || *p == '^') {
negate = 1;
++p;
}
while (*p && *p != ']') {
if (p[1] == '-' && p[2] != ']' && p[2] != 0) {
/* range [a-z] */
unsigned char start = (unsigned char)*p;
unsigned char end = (unsigned char)p[2];
unsigned char c = (unsigned char)t;
#ifdef WIN32
start = tolower(start);
end = tolower(end);
c = tolower(c);
#endif
if (c >= start && c <= end)
matched = 1;
p += 3;
} else {
/* single character */
if (char_match(*p, t))
matched = 1;
++p;
}
}
if (*p == ']')
++p;
if (negate)
matched = !matched;
if (!matched)
return 0;
return p;
}
/**
* Helper function to check end of match condition
*/
static inline int wnmatch_end(const char* t, int match_sub)
{
if (match_sub) {
/* match successfully only if we are at a directory border */
return *t != '/';
} else {
/* match successfully if we've consumed all text */
return *t != 0;
}
}
static inline int is_wild_escape(char c)
{
return c == '*'
|| c == '?'
|| c == '['
|| c == ']'
#ifdef _WIN32
|| c == '^';
#else
|| c == '\\';
#endif
}
/**
* Match with the previous pattern character provided in prev.
*
* An initial '**' needs to know if it was preceded by '/' to distinguish
* between multi-directory recursive matching (like /##.ext) and single-directory
* matching (like ##.ext).
*/
int wnmatch_sub_prev(const char* p, const char* t, int match_sub, char prev)
{
while (*p) {
char p0 = *p;
switch (p0) {
#ifdef _WIN32
case '^' :
#else
case '\\' :
#endif
/*
* Escape wildcard metacharacters.
*
* If the following character is not escapable, the
* escape character itself is matched literally.
*/
if (is_wild_escape(p[1]))
++p;
if (*t == 0 || !char_match(*p, *t))
return 1;
++p;
++t;
break;
case '?' :
/* ? matches any single character except / */
if (*t == 0 || *t == '/')
return 1;
++p;
++t;
break;
case '*' :
/* check for ** */
if (p[1] == '*') {
/* skip the ** */
p += 2;
/* munge all * */
while (*p == '*')
++p;
/* if its not near a slash, it's like a single * */
if (prev == '/' || *p == '/') {
/* a ** at end matches everything */
if (*p == 0)
return 0;
/*
* In between slashes matches to nothing
*
* Check for /##/ or ^##/ (^ start of string)
*
* This is required for:
* "/##/file.txt" matching "/file.txt"
* "##/file.txt" matching "file.txt"
* "x##/file.txt" NOT matching "xfile.txt"
*/
if (*p == '/' && (prev == 0 || prev == '/')) {
/* try reducing to nothing */
if (wnmatch_sub(p + 1, t, match_sub) == 0)
return 0;
/* otherwise / should match in the text */
}
/* try matching with 0 or more characters */
while (*t) {
if (wnmatch_sub(p, t, match_sub) == 0)
return 0;
++t;
}
/* try matching at the end */
return wnmatch_sub(p, t, match_sub);
}
} else {
/* skip the * */
++p;
}
/* a * at end matches rest of segment */
if (*p == 0) {
while (*t && *t != '/')
++t;
return wnmatch_end(t, match_sub);
}
/* try matching with 0 or more characters */
while (*t && *t != '/') {
if (wnmatch_sub(p, t, match_sub) == 0)
return 0;
++t;
}
/* try matching at the end */
return wnmatch_sub(p, t, match_sub);
case '[' :
/* character class */
if (*t == 0 || *t == '/')
return 1;
p = match_class(p + 1, *t);
if (!p)
return 1;
++t;
break;
default :
/* literal character */
if (*t == 0 || !char_match(*p, *t))
return 1;
++p;
++t;
break;
}
prev = p0;
}
return wnmatch_end(t, match_sub);
}
int wnmatch_sub(const char* p, const char* t, int match_sub)
{
return wnmatch_sub_prev(p, t, match_sub, 0);
}

View file

@ -1,168 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2025 Andrea Mazzoleni
#ifndef STR_H
#define STR_H
#include "app.h"
#include "str.h"
/****************************************************************************/
/* string */
/**
* Polish a string.
*
* Not printable chars are replaced by spaces.
*
* Note that the passed string is modified.
*/
char* strpolish(char* s);
/**
* Split a string into tokens in-place.
*
* Scans @str for tokens separated by any character in @delimiters,
* null-terminates each token by overwriting its trailing delimiter,
* and stores a pointer to each token's start in @split_map.
*
* If @trim_empty is non-zero, leading and consecutive delimiters are
* silently skipped, and tokens trimmed to empty are discarded.
* If @trim_empty is zero, empty tokens are preserved.
*
* The input string is modified in-place; @split_map entries point
* directly into @str and are only valid for its lifetime.
*
* \param split_map Output array receiving pointers to each token.
* \param split_max Capacity of @split_map; at most this many tokens are stored.
* \param str Input string to tokenise (modified in-place).
* \param delimiters Null-terminated set of delimiter characters.
* \param trim Null-terminated set of characters to trim from the start and end of each token.
* \param trim_empty Whether to trim empty tokens and consecutive delimiters.
* \return Number of tokens stored in @split_map.
*
* Example:
* char buf[] = " one, two,, , three ";
* char* map[8];
* unsigned n = strsplit(map, 8, buf, ",", " ", 1);
* // n == 3, map[] == { "one", "two", "three" }
*/
unsigned strsplit(char** split_map, unsigned split_max, char* str, const char* delimiters, const char* trim, int trim_empty);
/**
* Split a command-line string into an argument vector,
* applying the quoting rules of the platform's native shell.
*
* The input string is modified in-place: quotes and escape characters
* are stripped and each token is null-terminated. Whitespace is the
* implicit token delimiter on both platforms.
*
* bash quoting (Linux / macOS):
* 'single quotes' - Everything literal; no escapes processed inside.
* "double quotes" - '\' only escapes $, `, ", '\', and newline;
* all other backslashes are kept as-is.
* \x (unquoted) - Next character taken literally (even whitespace).
*
* cmd.exe quoting (Windows):
* "double quotes" - Toggle quoted mode; inside, '^' is NOT special.
* ^x (unquoted) - Next character taken literally.
* Single quotes and '\' carry no special meaning in either mode.
*
* \param split_map Output array receiving pointers to each argument.
* \param split_max Capacity of @split_map; at most this many tokens are stored.
* \param str Input command-line string (modified in-place).
* \return Number of arguments stored in @split_map.
*
* Example (bash):
* char buf[] = "one 'two three' \"say \\\"hi\\\"\" back\\slash";
* char* map[8];
* unsigned n = argsplit(map, 8, buf);
* // n==4, map[] == { "one", "two three", "say \"hi\"", "backslash" }
*
* Example (cmd.exe):
* char buf[] = "one \"two three\" ^&safe ^\"quoted^\"";
* char* map[8];
* unsigned n = argsplit(map, 8, buf);
* // n==4, map[] == { "one", "two three", "&safe", "\"quoted\"" }
*/
unsigned argsplit(const char** split_map, unsigned split_max, char* str);
/**
* Trim spaces from the start and the end
*/
char* strtrim(char* s);
/**
* Lower case
*/
char* strlwr(char* s);
/**
* Find the first occurrence of 'needle' in 'haystack' only if it
* appears as a separate word (space, number or string boundaries).
*
* Returns a pointer to the beginning of the match, or NULL if not found.
*/
char* worddigitstr(const char* haystack, const char* needle);
/**
* Convert a string to an integer, with the same semantics as strtol.
*/
int strtoi(const char* nptr, char** endptr, int base);
/**
* Convert a string to an unsigned integer, with the same semantics as strtoul.
*/
unsigned strtou(const char* nptr, char** endptr, int base);
/**
* Convert strings to non-negative unsigned integers.
* Negative or out-of-range values are rejected by returning (type)-1,
* setting errno to ERANGE, and setting endptr to nptr.
*/
unsigned strton(const char* nptr, char** endptr, int base);
unsigned long strtonl(const char* nptr, char** endptr, int base);
unsigned long long strtonll(const char* nptr, char** endptr, int base);
/****************************************************************************/
/* match */
/**
* Wild match function.
*
* If match_sub is !=0, it matches sub directory. Specifically it matches if the
* string "t" is not fully consumed and the next character to consume is a /.
*
* - ? matches any single character except /
* - * matches any sequence of characters except /
* - ** (nearby a /) matches everything including /
* - ** (not near a /) like *
* - ##/ reduces to nothing in addition to the normal matching of ** (using # instead of * to not mess the C comment)
* - [...] matches character classes with support for ranges and negation lile [!...] or [^...], except /
* - \ (Unix) or ^ (Windows) escapes *, ?, [, ], and the escape character itself
*
* \return 0 if it matches
*/
int wnmatch_sub(const char* p, const char* t, int match_sub);
/**
* Match with the pattern character immediately before p provided as prev context.
*
* This is needed for absolute filters where the leading '/' in the filter pattern
* is stripped before calling match (because target paths do not have a leading slash).
* Providing prev='/' preserves the information that an initial '**' was preceded by
* a slash, enabling recursive multi-directory matching (e.g. /##.ext or /##foo,
* using # instead of * to avoid C comment delimiter collision).
*
* Recursive sub-matches intentionally start with prev=0 because intermediate matching
* evaluates suffixes where preceding pattern characters are tracked in the loop.
*/
int wnmatch_sub_prev(const char* p, const char* t, int match_sub, char prev);
static inline int wnmatch(const char* p, const char* t)
{
return wnmatch_sub(p, t, 0);
}
#endif

View file

@ -1,865 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
#include "os/portable.h"
#include "support.h"
#include "util.h"
#include "stream.h"
/****************************************************************************/
/* stream */
unsigned STREAM_SIZE = 64 * 1024;
STREAM* sopen_read(const char* file, int flags)
{
STREAM* s = malloc_nofail(sizeof(STREAM));
struct stat st;
int ret;
s->handle_size = 1;
s->handle = malloc_nofail(sizeof(struct stream_handle));
s->advise = malloc_nofail(sizeof(struct advise_struct));
s->flags = flags;
advise_init(&s->advise[0], s->flags & STREAM_FLAGS_ADVISE_MASK);
int open_flags = O_RDONLY | O_BINARY | advise_flags(&s->advise[0]);
if ((s->flags & STREAM_FLAGS_NOFOLLOW) != 0)
open_flags |= O_NOFOLLOW;
pathcpy(s->handle[0].path, sizeof(s->handle[0].path), file);
s->handle[0].f = open(file, open_flags);
if (s->handle[0].f == -1) {
free(s->advise);
free(s->handle);
free(s);
return 0;
}
/* get file info */
if (fstat(s->handle[0].f, &st) != 0) {
close(s->handle[0].f);
free(s->advise);
free(s->handle);
free(s);
return 0;
}
s->size = st.st_size;
ret = advise_open(&s->advise[0], s->handle[0].f);
if (ret != 0) {
/* LCOV_EXCL_START */
close(s->handle[0].f);
free(s->advise);
free(s->handle);
free(s);
return 0;
/* LCOV_EXCL_STOP */
}
s->buffer_size = STREAM_SIZE;
if (s->buffer_size > s->size)
s->buffer_size = s->size; /* allocate only what is necessary */
s->buffer = malloc_nofail(s->buffer_size);
mtest_vector(1, s->buffer_size, (void**)&s->buffer);
s->pos = s->buffer;
s->end = s->buffer;
s->state = STREAM_STATE_READ;
s->state_index = 0;
s->offset = 0;
s->offset_uncached = 0;
s->crc = 0;
s->crc_uncached = 0;
return s;
}
STREAM* sopen_multi_write(unsigned count, int flags)
{
unsigned i;
STREAM* s = malloc_nofail(sizeof(STREAM));
s->handle_size = count;
s->handle = nalloc_nofail(count, sizeof(struct stream_handle));
s->advise = nalloc_nofail(count, sizeof(struct advise_struct));
s->flags = flags;
for (i = 0; i < count; ++i) {
s->handle[i].f = -1;
advise_init(&s->advise[i], s->flags & STREAM_FLAGS_ADVISE_MASK);
}
s->buffer_size = STREAM_SIZE;
s->buffer = malloc_nofail(s->buffer_size);
mtest_vector(1, s->buffer_size, (void**)&s->buffer);
s->pos = s->buffer;
s->end = s->buffer + s->buffer_size;
s->state = STREAM_STATE_WRITE;
s->state_index = 0;
s->size = 0;
s->offset = 0;
s->offset_uncached = 0;
s->crc = 0;
s->crc_uncached = 0;
return s;
}
int sopen_multi_file(STREAM* s, unsigned i, const char* file)
{
int f;
pathcpy(s->handle[i].path, sizeof(s->handle[i].path), file);
int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_BINARY | advise_flags(&s->advise[i]);
/* O_EXCL to be resilient ensure to always create a new file and not use a stale link to the original file */
f = open(file, open_flags, 0600);
if (f == -1) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
{
int ret;
ret = advise_open(&s->advise[i], f);
if (ret != 0) {
/* LCOV_EXCL_START */
close(f);
return -1;
/* LCOV_EXCL_STOP */
}
}
s->handle[i].f = f;
return 0;
}
STREAM* sopen_write(const char* file, int flags)
{
STREAM* s = sopen_multi_write(1, flags);
if (sopen_multi_file(s, 0, file) != 0) {
sclose(s);
return 0;
}
return s;
}
int sclose(STREAM* s)
{
int fail = 0;
unsigned i;
if (s->state == STREAM_STATE_WRITE) {
if (sflush(s) != 0) {
/* LCOV_EXCL_START */
fail = 1;
/* LCOV_EXCL_STOP */
}
}
for (i = 0; i < s->handle_size; ++i) {
/* if open failed, there is nothing to close */
if (s->handle[i].f != -1) {
if (advise_close(&s->advise[i], s->handle[i].f) != 0) {
/* LCOV_EXCL_START */
fail = 1;
/* LCOV_EXCL_STOP */
}
if (close(s->handle[i].f) != 0) {
/* LCOV_EXCL_START */
fail = 1;
/* LCOV_EXCL_STOP */
}
}
}
free(s->advise);
free(s->handle);
free(s->buffer);
free(s);
if (fail) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
return 0;
}
int shandle(STREAM* s)
{
if (!s->handle_size) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
return s->handle[0].f;
}
/**
* Fill the read stream buffer.
* \return 0 if at least on char is read, or EOF on error.
*/
static int sfill(STREAM* s)
{
ssize_t ret;
if (s->state != STREAM_STATE_READ) {
/* LCOV_EXCL_START */
return EOF;
/* LCOV_EXCL_STOP */
}
/* expose the logical size boundary as EOF, just like EOF from the underlying file */
if (s->offset >= s->size) {
s->state = STREAM_STATE_EOF;
return EOF;
}
ret = read(s->handle[0].f, s->buffer, s->buffer_size);
if (ret < 0) {
/* LCOV_EXCL_START */
s->state = STREAM_STATE_ERROR;
return EOF;
/* LCOV_EXCL_STOP */
}
if (ret == 0) {
/* nothing mode to read */
s->state = STREAM_STATE_EOF;
return EOF;
}
/* assume that it can be a shorter read, so ret < s->buffer_size doesn't mean that we reached EOF */
if (advise_read(&s->advise[0], s->handle[0].f, s->offset, ret) != 0) {
/* LCOV_EXCL_START */
s->state = STREAM_STATE_ERROR;
return EOF;
/* LCOV_EXCL_STOP */
}
/* update the crc */
if (s->flags & STREAM_FLAGS_CRC) {
s->crc_uncached = s->crc;
s->crc = crc32c(s->crc, s->buffer, ret);
}
/* update the offset */
s->offset_uncached = s->offset;
s->offset += ret;
s->pos = s->buffer;
s->end = s->buffer + ret;
return 0;
}
int sdeplete(STREAM* s, unsigned char* last)
{
/* last four bytes */
last[0] = 0;
last[1] = 0;
last[2] = 0;
last[3] = 0;
while (1) {
/* increase the position up to 4 bytes before the end */
if (s->end - s->pos >= 4)
s->pos = s->end - 4;
/* insert the last 4 bytes */
while (s->pos < s->end) {
last[0] = last[1];
last[1] = last[2];
last[2] = last[3];
last[3] = *s->pos++;
}
/* fill again the buffer until the end of the file */
if (sfill(s) != 0) {
/* on error fail */
if (serror(s)) {
/* LCOV_EXCL_START */
return EOF;
/* LCOV_EXCL_STOP */
}
/* on EOF terminate */
break;
}
}
return 0;
}
int sflush(STREAM* s)
{
ssize_t ret;
ssize_t size;
ssize_t count;
unsigned i;
if (s->state != STREAM_STATE_WRITE) {
/* LCOV_EXCL_START */
return EOF;
/* LCOV_EXCL_STOP */
}
size = s->pos - s->buffer;
if (!size)
return 0;
for (i = 0; i < s->handle_size; ++i) {
count = 0;
do {
ret = write(s->handle[i].f, s->buffer + count, size - count);
if (ret < 0) {
if (errno == EINTR)
continue;
/* LCOV_EXCL_START */
s->state = STREAM_STATE_ERROR;
s->state_index = i;
return EOF;
/* LCOV_EXCL_STOP */
}
if (ret == 0) {
/* LCOV_EXCL_START */
errno = EIO;
s->state = STREAM_STATE_ERROR;
s->state_index = i;
return EOF;
/* LCOV_EXCL_STOP */
}
count += ret;
} while (count < size);
}
for (i = 0; i < s->handle_size; ++i) {
/* ADVISE_DISCARD modes only discard ranges after waiting for writeback. */
if (advise_write(&s->advise[i], s->handle[i].f, s->offset, size) != 0) {
/* LCOV_EXCL_START */
s->state = STREAM_STATE_ERROR;
s->state_index = i;
return EOF;
/* LCOV_EXCL_STOP */
}
}
/*
* Update the crc *after* writing the data.
*
* This must be done after the file write,
* to be able to detect memory errors on the buffer,
* happening during the write.
*/
if (s->flags & STREAM_FLAGS_CRC) {
s->crc = crc32c(s->crc, s->buffer, size);
s->crc_uncached = s->crc;
}
/* update the offset */
s->offset += size;
s->offset_uncached = s->offset;
s->pos = s->buffer;
return 0;
}
int64_t stell(STREAM* s)
{
return s->offset_uncached + (s->pos - s->buffer);
}
uint32_t scrc(STREAM* s)
{
assert(s->flags & STREAM_FLAGS_CRC);
return crc32c(s->crc_uncached, s->buffer, s->pos - s->buffer);
}
int sgetc_uncached(STREAM* s)
{
/* if at the end of the buffer, fill it */
if (s->pos == s->end && sfill(s) != 0)
return EOF;
return *s->pos++;
}
ssize_t sgettok(STREAM* f, char* str, int size)
{
char* i = str;
char* send = str + size;
int c;
while (1) {
c = sgetc(f);
if (c == EOF) {
break;
}
if (c == ' ' || c == '\t') {
sungetc(c, f);
break;
}
if (c == '\n') {
/* remove ending carriage return to support the Windows CR+LF format */
if (i != str && i[-1] == '\r')
--i;
sungetc(c, f);
break;
}
*i++ = c;
if (i == send) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
}
*i = 0;
return i - str;
}
int sread_uncached(STREAM* f, void* void_data, size_t size)
{
unsigned char* data = void_data;
/* standard version using sgetc() */
while (size--) {
int c = sgetc(f);
if (c == EOF) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
*data++ = c;
}
return 0;
}
ssize_t sgetline(STREAM* f, char* str, int size)
{
char* i = str;
char* send = str + size;
int c;
/* if there is enough data in memory */
if (sptrlookup(f, size)) {
/* optimized version with all the data in memory */
unsigned char* pos = sptrget(f);
while (1) {
c = *pos++;
if (c == '\n') {
/* remove ending carriage return to support the Windows CR+LF format */
if (i != str && i[-1] == '\r')
--i;
--pos;
break;
}
if (i + 1 >= send) {
/* LCOV_EXCL_START */
*i = 0;
--pos;
sptrset(f, pos);
return -1;
/* LCOV_EXCL_STOP */
}
*i++ = c;
}
sptrset(f, pos);
} else {
while (1) {
c = sgetc(f);
if (c == EOF) {
/* LCOV_EXCL_START */
break;
/* LCOV_EXCL_STOP */
}
if (c == '\n') {
/* remove ending carriage return to support the Windows CR+LF format */
if (i != str && i[-1] == '\r')
--i;
sungetc(c, f);
break;
}
if (i + 1 >= send) {
/* LCOV_EXCL_START */
*i = 0;
sungetc(c, f);
return -1;
/* LCOV_EXCL_STOP */
}
*i++ = c;
}
}
*i = 0;
return i - str;
}
ssize_t sgetlasttok(STREAM* f, char* str, int size)
{
ssize_t ret;
ret = sgetline(f, str, size);
if (ret < 0) {
/* LCOV_EXCL_START */
return ret;
/* LCOV_EXCL_STOP */
}
while (ret > 0 && (str[ret - 1] == ' ' || str[ret - 1] == '\t'))
--ret;
str[ret] = 0;
return ret;
}
int sgetu32(STREAM* f, uint32_t* value)
{
int c;
c = sgetc(f);
if (c == '0') {
*value = 0;
return 0;
} else if (c >= '1' && c <= '9') {
uint32_t v;
v = c - '0';
c = sgetc(f);
while (c >= '0' && c <= '9') {
uint32_t digit;
if (v > 0xFFFFFFFFU / 10) {
/* LCOV_EXCL_START */
/* overflow */
return -1;
/* LCOV_EXCL_STOP */
}
v *= 10;
digit = c - '0';
if (v > 0xFFFFFFFFU - digit) {
/* LCOV_EXCL_START */
/* overflow */
return -1;
/* LCOV_EXCL_STOP */
}
v += digit;
c = sgetc(f);
}
*value = v;
sungetc(c, f);
return 0;
} else {
/* LCOV_EXCL_START */
/* nothing read */
return -1;
/* LCOV_EXCL_STOP */
}
}
int sgetb32(STREAM* f, uint32_t* value)
{
uint32_t v;
unsigned char b;
unsigned s;
int c;
v = 0;
s = 0;
loop:
c = sgetc(f);
if (c == EOF) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
b = (unsigned char)c;
if ((b & 0x80) == 0) {
v |= (uint32_t)b << s;
s += 7;
if (tommy_unlikely(s >= 32)) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
goto loop;
}
/*
* Check for overflow: at s == 28 only 4 bits (0x0f) fit in uint32_t
*/
if (tommy_unlikely(s == 28 && (b & 0x70) != 0)) {
return -1;
}
v |= (uint32_t)(b & 0x7f) << s;
*value = v;
return 0;
}
int sgetb64(STREAM* f, uint64_t* value)
{
uint64_t v;
unsigned char b;
unsigned s;
int c;
v = 0;
s = 0;
loop:
c = sgetc(f);
if (c == EOF) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
b = (unsigned char)c;
if ((b & 0x80) == 0) {
v |= (uint64_t)b << s;
s += 7;
if (tommy_unlikely(s >= 64)) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
goto loop;
}
/*
* Check for overflow: at s == 63 only 1 bit (0x01) fits in uint64_t
*/
if (tommy_unlikely(s == 63 && (b & 0x7e) != 0)) {
return -1;
}
v |= (uint64_t)(b & 0x7f) << s;
*value = v;
return 0;
}
int sgetble32(STREAM* f, uint32_t* value)
{
unsigned char buf[4];
if (sread(f, buf, 4) != 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
*value = buf[0] | (uint32_t)buf[1] << 8 | (uint32_t)buf[2] << 16 | (uint32_t)buf[3] << 24;
return 0;
}
ssize_t sgetbs(STREAM* f, char* str, size_t size)
{
uint64_t len;
if (sgetb64(f, &len) < 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
if (len >= size) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
str[len] = 0;
if (sread(f, str, len) != 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
return len;
}
int swrite_uncached(const void* void_data, size_t size, STREAM* f)
{
const unsigned char* data = void_data;
while (size) {
size_t available;
if (f->pos == f->end) {
if (sflush(f) != 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
}
available = (size_t)(f->end - f->pos);
if (available > size)
available = size;
memcpy(f->pos, data, available);
f->pos += available;
data += available;
size -= available;
}
return 0;
}
int sputb32(uint32_t value, STREAM* s)
{
unsigned char b;
unsigned char buf[16];
unsigned i;
i = 0;
loop:
b = value & 0x7f;
value >>= 7;
if (value) {
buf[i++] = b;
goto loop;
}
buf[i++] = b | 0x80;
return swrite(buf, i, s);
}
int sputb64(uint64_t value, STREAM* s)
{
unsigned char b;
unsigned char buf[16];
unsigned i;
i = 0;
loop:
b = value & 0x7f;
value >>= 7;
if (value) {
buf[i++] = b;
goto loop;
}
buf[i++] = b | 0x80;
return swrite(buf, i, s);
}
int sputble32(uint32_t value, STREAM* s)
{
unsigned char buf[4];
buf[0] = value & 0xFF;
buf[1] = (value >> 8) & 0xFF;
buf[2] = (value >> 16) & 0xFF;
buf[3] = (value >> 24) & 0xFF;
return swrite(buf, 4, s);
}
int sputbs(const char* str, STREAM* f)
{
size_t len = strlen(str);
if (sputb64(len, f) != 0) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
return swrite(str, len, f);
}
#if HAVE_FSYNC
int ssync(STREAM* s)
{
unsigned i;
for (i = 0; i < s->handle_size; ++i) {
int ret;
/*
* On macOS, standard fsync() only pushes data from kernel buffers to the
* drive's volatile cache without requesting a physical media flush. F_FULLFSYNC
* forces the drive controller to commit all cached data to permanent storage.
*/
#if defined(__APPLE__) && defined(F_FULLFSYNC)
ret = fcntl(s->handle[i].f, F_FULLFSYNC);
if (ret != 0 && (errno == ENOTSUP || errno == EINVAL))
ret = fsync(s->handle[i].f);
#else
ret = fsync(s->handle[i].f);
#endif
if (ret != 0) {
/* LCOV_EXCL_START */
s->state = STREAM_STATE_ERROR;
s->state_index = i;
return -1;
/* LCOV_EXCL_STOP */
}
}
return 0;
}
#endif
int smtime(STREAM* s, int64_t mtime_sec, int mtime_nsec)
{
unsigned i;
for (i = 0; i < s->handle_size; ++i) {
if (s->handle[i].f != -1 && fmtime(s->handle[i].f, mtime_sec, mtime_nsec) != 0) {
/* LCOV_EXCL_START */
s->state = STREAM_STATE_ERROR;
s->state_index = i;
return -1;
/* LCOV_EXCL_STOP */
}
}
return 0;
}

View file

@ -1,415 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
#ifndef STREAM_H
#define STREAM_H
#include "support.h"
#include "util.h"
/****************************************************************************/
/* stream */
#define STREAM_FLAGS_ADVISE_MASK 0xFF /**< Low bits containing one of ADVISE_*. */
#define STREAM_FLAGS_CRC 0x100 /**< Enable the CRC computation. */
#define STREAM_FLAGS_NOFOLLOW 0x200 /**< Don't follow the final symbolic link on open. */
/**
* Size of the buffer of the stream.
*
* It's not a constant for testing purpose.
*/
extern unsigned STREAM_SIZE;
#define STREAM_STATE_READ 0 /**< The stream is in a normal state of read. */
#define STREAM_STATE_WRITE 1 /**< The stream is in a normal state of write. */
#define STREAM_STATE_ERROR -1 /**< An error was encountered. */
#define STREAM_STATE_EOF 2 /**< The end of file was encountered. */
struct stream_handle {
int f; /**< Handle of the file. */
char path[PATH_MAX]; /**< Path of the file. */
};
struct stream {
unsigned char* buffer; /**< Buffer of the stream. */
off_t buffer_size; /**< Size of the buffer */
unsigned char* pos; /**< Current position in the buffer. */
unsigned char* end; /**< End position of the buffer. */
struct stream_handle* handle; /**< Set of handles. */
off_t offset; /**< Offset into the file. */
off_t offset_uncached; /**< Offset into the file excluding the cached data. */
off_t size; /**< File size, only in read */
int flags; /**< Flags passed on open */
int state; /**< State of the stream. One of STREAM_STATE. */
int state_index; /**< Index of the handle causing a state change. */
unsigned handle_size; /**< Number of handles. */
/**
* CRC of the data read or written in the file.
*
* If reading, it's the CRC of all data read from the file,
* including the one in the buffer.
* If writing it's all the data wrote to the file,
* excluding the one still in buffer yet to be written.
*/
uint32_t crc;
/**
* CRC of the file excluding the cached data in the buffer.
*
* If reading, it's the CRC of the data read from the file,
* excluding the one in the buffer.
* If writing it's all the data wrote to the file,
* excluding the one still in buffer yet to be written.
*/
uint32_t crc_uncached;
struct advise_struct* advise; /**< Cache advice state for each handle. */
};
/**
* Opaque STREAM type. Like ::FILE.
*/
typedef struct stream STREAM;
/**
* Open a stream for reading. Like fopen("r").
*/
STREAM* sopen_read(const char* file, int flags);
/**
* Open a stream for writing. Like fopen("w").
*/
STREAM* sopen_write(const char* file, int flags);
/**
* Open a set of streams for writing. Like fopen("w").
*/
STREAM* sopen_multi_write(unsigned count, int flags);
/**
* Specify the file to open.
*/
int sopen_multi_file(STREAM* s, unsigned i, const char* file);
/**
* Close a stream. Like fclose().
*/
int sclose(STREAM* s);
/**
* Return the handle of the file.
* In case of multi file, the first one is returned.
*/
int shandle(STREAM* s);
/**
* Read the stream until the end, and return the latest 4 chars.
* The CRC of the file is also computed, and you can get it using scrc().
* \return 0 on success, or EOF on error.
*/
int sdeplete(STREAM* s, unsigned char* last);
/**
* Flush the write stream buffer.
* \return 0 on success, or EOF on error.
*/
int sflush(STREAM* s);
/**
* Get the file pointer.
*/
int64_t stell(STREAM* s);
/**
* Get the CRC of the processed data.
*/
uint32_t scrc(STREAM* s);
/**
* Check if the buffer has enough data loaded.
*/
static inline int sptrlookup(STREAM* s, size_t size)
{
/* compute remaining distance to avoid pointer arithmetic out of buffer bounds */
return size <= (size_t)(s->end - s->pos);
}
/**
* Get the current stream ptr.
*/
static inline unsigned char* sptrget(STREAM* s)
{
return s->pos;
}
/**
* Set the current stream ptr.
*/
static inline void sptrset(STREAM* s, unsigned char* ptr)
{
s->pos = ptr;
}
/**
* Check the error status. Like ferror().
*/
static inline int serror(STREAM* s)
{
return s->state == STREAM_STATE_ERROR;
}
/**
* Check the eof status. Like feof().
*/
static inline int seof(STREAM* s)
{
return s->state == STREAM_STATE_EOF;
}
/**
* Get the index of the handle that caused the error.
*/
static inline int serrorindex(STREAM* s)
{
return s->state_index;
}
/**
* Get the path of the handle that caused the error.
*/
static inline const char* serrorfile(STREAM* s)
{
return s->handle[s->state_index].path;
}
/**
* Sync the stream. Like fsync().
*/
int ssync(STREAM* s);
/**
* Change the modification time of all files in the stream.
*/
int smtime(STREAM* s, int64_t mtime_sec, int mtime_nsec);
/****************************************************************************/
/* get */
/**
* \internal Used by sgetc().
* \note Don't call this directly, but use sgetc().
*/
int sgetc_uncached(STREAM* s);
/**
* Read a char. Like fgetc().
*/
static inline int sgetc(STREAM* s)
{
if (tommy_unlikely(s->pos == s->end))
return sgetc_uncached(s);
return *s->pos++;
}
/**
* Unread a char.
* Like ungetc() but you have to unget the same char read.
*/
static inline void sungetc(int c, STREAM* s)
{
if (c != EOF)
--s->pos;
}
/**
* \internal Used by sread() when the requested data crosses the buffered range.
* \note Don't call this directly, but use sread().
*/
int sread_uncached(STREAM* f, void* void_data, size_t size);
/**
* Read a fixed amount of chars.
* Return 0 on success, or -1 on error.
*/
static inline int sread(STREAM* f, void* void_data, size_t size)
{
if (tommy_unlikely(!sptrlookup(f, size)))
return sread_uncached(f, void_data, size);
memcpy(void_data, f->pos, size);
f->pos += size;
return 0;
}
/**
* Get a char from a stream, ignoring one '\r'.
*/
static inline int sgeteol(STREAM* f)
{
int c;
c = sgetc(f);
if (c == '\r')
c = sgetc(f);
return c;
}
/**
* Read all the spaces and tabs.
* Return the number of spaces and tabs read.
*/
static inline int sgetspace(STREAM* f)
{
int count = 0;
int c;
c = sgetc(f);
while (c == ' ' || c == '\t') {
++count;
c = sgetc(f);
}
sungetc(c, f);
return count;
}
/**
* Read until the first space or tab.
* Stop at the first ' ', '\t', '\n' or EOF.
* Return <0 if the buffer is too small, or the number of chars read.
*/
ssize_t sgettok(STREAM* f, char* str, int size);
/**
* Read until the end of line.
* Stop at the first '\n' or EOF. Note that '\n' is left in the stream.
* Return <0 if the buffer is too small, or the number of chars read.
*/
ssize_t sgetline(STREAM* f, char* str, int size);
/**
* Like sgetline() but remove ' ' and '\t' at the end.
*/
ssize_t sgetlasttok(STREAM* f, char* str, int size);
/**
* Read a 32 bit number.
* Stop at the first not digit char or EOF.
* Return <0 if there isn't enough to read.
*/
int sgetu32(STREAM* f, uint32_t* value);
/****************************************************************************/
/* binary get */
/**
* Read a binary 32 bit number in packet format.
* Return <0 if there isn't enough to read.
*/
int sgetb32(STREAM* f, uint32_t* value);
/**
* Read a binary 64 bit number in packet format.
* Return <0 if there isn't enough to read.
*/
int sgetb64(STREAM* f, uint64_t* value);
/**
* Read a binary 32 bit number in little endian format.
* Return <0 if there isn't enough to read.
*/
int sgetble32(STREAM* f, uint32_t* value);
/**
* Read a binary string.
* Return -1 on error or if the buffer is too small, or the number of chars read.
*/
ssize_t sgetbs(STREAM* f, char* str, size_t size);
/****************************************************************************/
/* put */
/**
* Write a char. Like fputc().
* Return 0 on success or -1 on error.
*/
static inline int sputc(int c, STREAM* s)
{
if (s->pos == s->end) {
if (sflush(s) != 0)
return -1;
}
*s->pos++ = c;
return 0;
}
/**
* Write a end of line.
* Return 0 on success or -1 on error.
*/
static inline int sputeol(STREAM* s)
{
#ifdef _WIN32
if (sputc('\r', s) != 0)
return -1;
#endif
return sputc('\n', s);
}
/**
* \internal Used by swrite() when the data crosses the buffered range.
* \note Don't call this directly, but use swrite().
*/
int swrite_uncached(const void* data, size_t size, STREAM* f);
/**
* Write a sized buffer.
* Return 0 on success or -1 on error.
*/
static __always_inline int swrite(const void* data, size_t size, STREAM* f)
{
if (tommy_unlikely(!sptrlookup(f, size)))
return swrite_uncached(data, size, f);
memcpy(f->pos, data, size);
f->pos += size;
return 0;
}
/****************************************************************************/
/* binary put */
/**
* Write a binary 32 bit number in packed format.
* Return 0 on success or -1 on error.
*/
int sputb32(uint32_t value, STREAM* s);
/**
* Write a binary 64 bit number in packed format.
* Return 0 on success or -1 on error.
*/
int sputb64(uint64_t value, STREAM* s);
/**
* Write a binary 32 bit number in little endian format.
* Return 0 on success or -1 on error.
*/
int sputble32(uint32_t value, STREAM* s);
/**
* Write a binary string.
* Return 0 on success or -1 on error.
*/
int sputbs(const char* str, STREAM* s);
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,496 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
#ifndef SUPPORT_H
#define SUPPORT_H
#include "app.h"
#include "memory.h"
#include "str.h"
/****************************************************************************/
/* lock */
/**
* Initialize and destroy the locks.
*/
void lock_init(void);
void lock_done(void);
/**
* Lock used for printf.
*
* In Windows printf() is not atomic, and multiple threads
* will have output interleaved.
*
* Note that even defining __USE_MINGW_ANSI_STDIO the problem persists.
*
* See for example:
*
* Weird output when I use pthread and printf.
* http://stackoverflow.com/questions/13190254/weird-output-when-i-use-pthread-and-printf
*
* This is also required in other OS because we split output in stdlog in
* two fprintf calls.
*/
void lock_msg(void);
void unlock_msg(void);
/****************************************************************************/
/* random */
/**
* Seed the random pseudo random number generator
*/
void random_seed(uint64_t seed);
/**
* Reseed the random pseudo random number generator with the tick count
*/
void random_reseed(void);
/**
* Return a pseudo random number of 8 bits
*/
unsigned char random_u8(void);
/**
* Return a pseudo random number of 64 bits
*/
uint64_t random_u64(void);
/****************************************************************************/
/* error */
/**
* Return if the error is at hardware level
*/
int is_hw(int err);
/**
* Return the number of hardware errors logged so far.
*/
unsigned log_hardware_errors(void);
/**
* Log errors with standard messages
*/
void log_fatal_errno(int err, const char* name);
void log_error_errno(int err, const char* name);
/****************************************************************************/
/* log */
/**
* Pointer to log function.
*/
typedef void log_ptr(int err, const char* format, ...) __attribute__((format(attribute_printf, 2, 3)));
/**
* Fatal error messages.
*
* Messages printed before an early termination.
*
* These messages go in the log file and in stderr, except in GUI mode
* when the tagged log message is emitted successfully.
*/
void vlog_fatal(int err, const char* format, va_list ap, const char* post);
void log_fatal(int err, const char* format, ...) __attribute__((format(attribute_printf, 2, 3)));
/**
* Unexpected error messages.
*
* Messages reporting error conditions that don't prevent the program to run.
*
* Some of them could be also serious errors, like "silent errors".
* In such case, the summary result is always printed as error,
* and we are sure to notify the user in some way.
*
* These messages go in the log file if specified, otherwise they go in stderr.
*/
void vlog_error(int err, const char* format, va_list ap, const char* post);
void log_error(int err, const char* format, ...) __attribute__((format(attribute_printf, 2, 3)));
/**
* Informational messages.
*
* Messages reporting general status information or warnings that do not indicate failure.
*
* These messages go in the log file if specified, otherwise they go in stderr.
*/
void log_info(int err, const char* format, ...) __attribute__((format(attribute_printf, 2, 3)));
/**
* Expected error messages, without fallback to stderr.
*
* These errors are "someway" expected, and then they never go to screen.
* For example, when undeleting missing files, the messages for missing files
* are not shown.
*
* These messages go in the log file if specified, otherwise they are lost.
*/
void log_expected(int err, const char* format, ...) __attribute__((format(attribute_printf, 2, 3)));
/**
* Tag messages.
*
* Messages are in tag format, like "tag:entry:...".
*
* These messages never go on the screen, but only in the log file if specified.
*
* Note that this function, allows not \n terminated strings.
*
* These messages are buffered. Use msg_flush() to flush them.
*/
void log_tag(const char* format, ...) __attribute__((format(attribute_printf, 1, 2)));
/**
* Flush the log.
*/
void log_flush(void);
/****************************************************************************/
/* message */
/**
* Pointer to msg function.
*/
typedef void msg_ptr(const char* format, ...) __attribute__((format(attribute_printf, 1, 2)));
/**
* Message levels.
*
* The levels control the amount of information printed on the screen.
* Note that log_fatal(), log_error(), log_expected() and log_tag() are not affected by this option.
*
* From the most quiet to the most verbose.
*/
#define MSG_STATUS -3
#define MSG_INFO -2
#define MSG_PROGRESS -1
#define MSG_BAR 0
#define MSG_VERBOSE 1
/**
* Selected message level.
*/
extern int msg_level;
/**
* Emit fatal messages on stderr also when a log is configured.
*/
extern int msg_fatal_stderr;
/**
* State messages.
*
* Messages that tell what the program is doing or did, but limited to few lines.
* They are status information, and summary results.
*/
void msg_status(const char* format, ...) __attribute__((format(attribute_printf, 1, 2)));
/**
* Info messages.
*
* Messages that tell what was done.
* Potentially a lot of messages are possible. They can still be on the screen,
* as losing them we don't lose information.
*
* These messages never go in the log file, because there is always a corresponding log_tag().
*/
void msg_info(const char* format, ...) __attribute__((format(attribute_printf, 1, 2)));
/**
* Progress messages.
*
* Message that tell the progress of program.
*
* These messages also go in the log file.
*/
void msg_progress(const char* format, ...) __attribute__((format(attribute_printf, 1, 2)));
/**
* Progress bar messages.
*
* Message that show the percentage of the progress.
*
* These messages never go in the log file.
*
* These messages are buffered. Use msg_flush() to flush them.
*/
void msg_bar(const char* format, ...) __attribute__((format(attribute_printf, 1, 2)));
/**
* Verbose messages.
*
* Message that tell what is already expected.
*
* These messages also go in the log file.
*/
void msg_verbose(const char* format, ...) __attribute__((format(attribute_printf, 1, 2)));
/**
* Flush the output.
*/
void msg_flush(void);
/****************************************************************************/
/* print */
/**
* Print a repeated char.
*/
void printc(char c, size_t pad);
/**
* Print a string with right space padding.
*/
void printr(const char* str, size_t pad);
/**
* Print a string with left space padding.
*/
void printl(const char* str, size_t pad);
/**
* Print a probability with space padding.
*/
void printp(double v, size_t pad);
/****************************************************************************/
/* escape */
#define ESC_MAX (PATH_MAX * 2 + 1)
#define ESC_POOL_MAX 8
/**
* Escape a string for the log.
*
* Chars ':', '\n', '\r' and '\' are escaped to '\d', '\\n', '\\r' and '\\'.
*/
const char* esc_tag(const char* str);
/**
* Get a dynamically allocated buffer of ESC_MAX size from a circular pool.
*/
char* esc_buf(void);
/**
* Escape a string for the shell.
*
* \param buffer Preallocated buffer of ESC_MAX size.
*/
const char* esc_shell_multi(const char** str_map, unsigned str_max, char* buffer);
static inline const char* esc_shell(const char* str, char* buffer)
{
return esc_shell_multi(&str, 1, buffer);
}
/****************************************************************************/
/* path */
/**
* Copy a path limiting the size.
* Abort if too long.
*/
void pathcpy(char* dst, size_t size, const char* src);
/**
* Concatenate a path limiting the size.
* Abort if too long.
*/
void pathcat(char* dst, size_t size, const char* src);
/**
* Concatenate a path limiting the size knowing the length.
* Abort if too long.
*/
void pathcatl(char* dst, size_t dst_len, size_t size, const char* src);
/**
* Concatenate a path limiting the size.
* Abort if too long.
*/
void pathcatc(char* dst, size_t size, char c);
/**
* Import a path limiting the size.
* In Windows all the backslash are converted to the C standard of forward slash.
* Abort if too long.
*/
void pathimport(char* dst, size_t size, const char* src);
/**
* Export a path limiting the size.
* In Windows all the C slashes are converted to the Windows backslash.
* Abort if too long.
*/
void pathexport(char* dst, size_t size, const char* src);
/**
* Print a path.
* Abort if too long.
*/
void pathprint(char* dst, size_t size, const char* format, ...) __attribute__((format(attribute_printf, 3, 4)));
/**
* Ensure the presence of a terminating slash, if it isn't empty.
* Abort if too long.
*/
void pathslash(char* dst, size_t size);
/**
* Cut everything after the latest slash.
*
* If the string doesn't contain any slash, it returns the empty string.
*/
void pathcut(char* dst);
/**
* Given a string ending with slash, remove that ending slash and any char up to the previous slash.
*
* If there are not more slash, it returns the empty string.
*/
void pathup(char* dst);
/**
* Compare two paths.
* In Windows it's case insensitive and assumes \ equal at /.
*/
int pathcmp(const char* a, const char* b);
/**
* Compare two paths up to n chars.
* In Windows it's case insensitive and assumes \ equal at /.
*/
int pathncmp(const char* a, const char* b, size_t n);
/**
* Check if the root is matching the start of the specified path.
*
* The root MUST end with a /.
*
* In Windows it's case insensitive and assumes \ equal at /.
*/
int path_is_root_of(const char* root, const char* path);
/**
* Check if the path is a canonical relative sub-path.
*
* A valid sub-path must:
* - Not be empty
* - Not start or end with a slash '/'
* - Not contain backslashes '\\' (on Windows)
* - Not start with a drive letter (e.g., "C:" on Windows)
* - Not contain empty components ("//"), "." or ".."
*/
int path_is_sub(const char* sub);
/****************************************************************************/
/* file-system */
/**
* Create all the ancestor directories if missing.
* The file name, after the last /, is ignored.
*/
int mkancestor(const char* file);
/**
* Change the modification time of an open file.
*/
int fmtime(int f, int64_t mtime_sec, int mtime_nsec);
/**
* Change the modification time of a file or link.
* Note that links are NOT deferenced.
*/
int lmtime(const char* path, int64_t mtime_sec, int mtime_nsec);
/****************************************************************************/
/* advise */
/**
* Advise modes.
*/
#define ADVISE_DEFAULT 0 /**< Default mode. */
#define ADVISE_NONE 1 /**< Bare read/write mode. */
#define ADVISE_SEQUENTIAL 2 /**< Sequential mode. */
#define ADVISE_FLUSH 3 /**< Flush mode. */
#define ADVISE_FLUSH_WINDOW 4 /**< Flush mode with a window of 8MB. */
#define ADVISE_DISCARD 5 /**< Discard the cache after every operation. */
#define ADVISE_DISCARD_WINDOW 6 /**< Discard the cache with a window of 8MB. */
#define ADVISE_DIRECT 7 /**< Direct mode. */
#define ADVISE_WINDOW_SIZE (8 * 1024 * 1024) /**< Window size. */
struct advise_struct {
int mode;
data_off_t dirty_begin;
data_off_t dirty_end;
};
void advise_init(struct advise_struct* advise, int mode);
int advise_flags(struct advise_struct* advise);
int advise_open(struct advise_struct* advise, int f);
int advise_write(struct advise_struct* advise, int f, data_off_t offset, data_off_t size);
int advise_read(struct advise_struct* advise, int f, data_off_t offset, data_off_t size);
int advise_close(struct advise_struct* advise, int f);
/****************************************************************************/
/* smartctl */
/**
* Read smartctl attributes from a stream.
* Return 0 on success.
*/
int smartctl_attribute(OS_FILE* f, const char* file, const char* name, struct smart_attr* smart, uint64_t* info, char* serial, char* family, char* model, char* interf);
/**
* Flush smartctl output from a stream.
*/
int smartctl_flush(OS_FILE* f, const char* file, const char* name);
/**
* Extract the temperature from the SMART info.
* Return -1 if missing
*/
int smart_temp(devinfo_t* devinfo);
/****************************************************************************/
/* thread */
#if HAVE_THREAD
/**
* Control when to signal the condition variables.
*
* Default is inside the mutex.
*
* Ensure to change that before starting any thread.
*/
extern int thread_cond_signal_outside;
/**
* Thread wrappers to handle error conditions.
*/
void thread_mutex_init(thread_mutex_t* mutex);
void thread_mutex_destroy(thread_mutex_t* mutex);
void thread_mutex_lock(thread_mutex_t* mutex);
void thread_mutex_unlock(thread_mutex_t* mutex);
void thread_cond_init(thread_cond_t* cond);
void thread_cond_destroy(thread_cond_t* cond);
void thread_cond_signal(thread_cond_t* cond);
void thread_cond_broadcast(thread_cond_t* cond);
void thread_cond_wait(thread_cond_t* cond, thread_mutex_t* mutex);
void thread_cond_signal_and_unlock(thread_cond_t* cond, thread_mutex_t* mutex);
void thread_cond_broadcast_and_unlock(thread_cond_t* cond, thread_mutex_t* mutex);
void thread_create(thread_id_t* thread, void* (*func)(void*), void* arg);
void thread_join(thread_id_t thread, void** retval);
void thread_yield(void);
int thread_key_create(thread_key_t* key, void (*destructor)(void*));
int thread_key_delete(thread_key_t key);
void* thread_getspecific(thread_key_t key);
int thread_setspecific(thread_key_t key, void* value);
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,432 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2025 Andrea Mazzoleni
#include "os/portable.h"
#include "thermal.h"
#include "state.h"
#include "io.h"
#include <math.h>
#include <float.h>
struct snapraid_thermal* thermal_alloc(uint64_t dev, const char* name)
{
struct snapraid_thermal* thermal = malloc_nofail(sizeof(struct snapraid_thermal));
thermal->device = dev;
thermal->latest_temperature = 0;
thermal->count = 0;
memset(&thermal->params, 0, sizeof(thermal->params));
pathcpy(thermal->name, sizeof(thermal->name), name);
return thermal;
}
void thermal_free(void* void_thermal)
{
struct snapraid_thermal* thermal = void_thermal;
free(thermal);
}
/**
* Fit exponential heating model to data using least squares
*/
struct snapraid_thermal_params fit_thermal_model(const struct snapraid_thermal_point* points, int n_points, double t_ambient)
{
struct snapraid_thermal_params model;
double t_steady_try;
double k_try;
memset(&model, 0, sizeof(model));
model.t_ambient = t_ambient;
/* at least four points to have a result */
if (n_points < 4)
return model;
double last_temp = points[n_points - 1].temperature;
/* iterative refinement to find best k_heat and t_steady */
double best_error = 1e10;
double best_k = 0;
double best_t_steady = 0;
/* grid search for parameters */
for (t_steady_try = last_temp + 2.0; t_steady_try <= last_temp + 25.0; t_steady_try += 0.5) {
for (k_try = 0.00001; k_try <= 0.001; k_try *= 1.2) {
double error = 0.0;
int i;
/* calculate error for this parameter set */
for (i = 0; i < n_points; i++) {
double t = points[i].time;
double t_predicted = t_steady_try - (t_steady_try - points[0].temperature) * exp(-k_try * t);
double diff = points[i].temperature - t_predicted;
error += diff * diff;
}
if (error < best_error) {
best_error = error;
best_k = k_try;
best_t_steady = t_steady_try;
}
}
}
model.k_heat = best_k;
model.t_steady = best_t_steady;
/* calculate quality metrics */
double sum_squared_residuals = 0.0;
double sum_total = 0.0;
double mean_temp = 0.0;
model.max_error = 0.0;
int i;
/* calculate mean temperature */
for (i = 0; i < n_points; i++)
mean_temp += points[i].temperature;
mean_temp /= n_points;
/* calculate R-squared and errors */
for (i = 0; i < n_points; i++) {
double t = points[i].time;
double t_predicted = model.t_steady - (model.t_steady - points[0].temperature) * exp(-model.k_heat * t);
double residual = points[i].temperature - t_predicted;
sum_squared_residuals += residual * residual;
sum_total += (points[i].temperature - mean_temp) * (points[i].temperature - mean_temp);
double abs_error = fabs(residual);
if (abs_error > model.max_error) {
model.max_error = abs_error;
}
}
model.rmse = sqrt(sum_squared_residuals / n_points);
/* avoid sum_total underflow and division by zero */
if (sum_total > FLT_EPSILON) {
model.r_squared = 1.0 - (sum_squared_residuals / sum_total);
} else {
model.r_squared = 1.0;
}
return model;
}
int state_thermal(struct snapraid_state* state, time_t now)
{
tommy_node* i;
unsigned j;
tommy_list high;
tommy_list low;
int ret;
if (state->thermal_temperature_limit == 0)
return 0;
/* reset the current highest temperature to ensure fail-open on measurement failure */
state->thermal_highest_temperature = 0;
state_devmap(state);
tommy_list_init(&high);
tommy_list_init(&low);
/* for all disks */
for (i = state->disklist; i != 0; i = i->next) {
struct snapraid_disk* disk = i->data;
devinfo_t* entry;
entry = calloc_nofail(1, sizeof(devinfo_t));
entry->device = disk->mount_device;
device_name_set(entry, disk->name, 0);
entry->is_array = 1;
pathcpy(entry->mount, sizeof(entry->mount), disk->mount_point);
pathcpy(entry->smartctl, sizeof(entry->smartctl), disk->smartctl);
pathcpy(entry->smartctl_info, sizeof(entry->smartctl_info), disk->smartctl_info);
memcpy(entry->smartignore, disk->smartignore, sizeof(entry->smartignore));
tommy_list_insert_tail(&high, &entry->node, entry);
}
/* for all parities */
for (j = 0; j < state->level; ++j) {
devinfo_t* entry;
unsigned s;
for (s = 0; s < state->parity[j].split_mac; ++s) {
entry = calloc_nofail(1, sizeof(devinfo_t));
entry->device = state->parity[j].split_map[s].device;
device_name_set(entry, lev_config_name(j), s);
entry->is_array = 1;
pathcpy(entry->mount, sizeof(entry->mount), state->parity[j].split_map[s].path);
pathcpy(entry->smartctl, sizeof(entry->smartctl), state->parity[j].smartctl);
pathcpy(entry->smartctl_info, sizeof(entry->smartctl_info), state->parity[j].smartctl_info);
memcpy(entry->smartignore, state->parity[j].smartignore, sizeof(entry->smartignore));
pathcut(entry->mount); /* remove the parity file */
tommy_list_insert_tail(&high, &entry->node, entry);
}
}
/* with a GUI always gives time reference */
if (state->opt.gui)
log_tag("unixtime:%" PRIi64 "\n", (int64_t)now);
if (state->opt.fake_device) {
ret = devtest(&high, &low, DEVICE_SMART);
} else {
ret = devquery(&high, &low);
if (ret == 0 && !tommy_list_empty(&low))
ret = devrun(&low, DEVICE_SMART);
}
/* on error, just disable thermal gathering */
if (ret != 0)
goto bail_error;
/* if the list is empty, it's not supported in this platform */
if (tommy_list_empty(&low))
goto bail_error;
/* report new attribute */
state_attr(state, &low);
/* if ambient temperature is not set, get the system temperature or fallback to the lowest HD temperature */
if (state->thermal_ambient_temperature == 0) {
state->thermal_system_temperature = ambient_temperature();
state->thermal_ambient_temperature = state->thermal_system_temperature;
if (state->thermal_ambient_temperature == 0) {
for (i = tommy_list_head(&low); i != 0; i = i->next) {
devinfo_t* devinfo = i->data;
int temp = smart_temp(devinfo);
if (temp < 0)
continue;
log_tag("thermal:system:candidate:%d\n", temp);
if (state->thermal_ambient_temperature == 0 || state->thermal_ambient_temperature > temp)
state->thermal_ambient_temperature = temp;
}
}
log_tag("thermal:system:final:%d\n", state->thermal_ambient_temperature);
}
int count = 0;
int highest_temperature = 0;
for (i = tommy_list_head(&low); i != 0; i = i->next) {
tommy_node* t;
struct snapraid_thermal* found;
devinfo_t* devinfo = i->data;
unsigned k;
int temperature = smart_temp(devinfo);
if (temperature < 0)
continue;
++count;
/* search of the entry */
found = 0;
for (t = tommy_list_head(&state->thermallist); t != 0; t = t->next) {
struct snapraid_thermal* thermal = t->data;
if (thermal->device == devinfo->device) {
found = thermal;
break;
}
}
/* if not found, create it */
if (found == 0) {
found = thermal_alloc(devinfo->device, devinfo->name);
tommy_list_insert_tail(&state->thermallist, &found->node, found);
}
found->latest_temperature = temperature;
if (highest_temperature < temperature)
highest_temperature = temperature;
log_tag("thermal:current:%s:%" PRIu64 ":%d\n", devinfo->name, devinfo->device, temperature);
if (state->thermal_stop_gathering)
continue;
if (found->count + 1 >= THERMAL_MAX) /* keep one extra space at the end */
continue;
/* only monotone increasing temperature */
if (found->count > 0 && found->data[found->count - 1].temperature >= temperature)
continue;
/* insert the new data point */
found->data[found->count].temperature = temperature;
found->data[found->count].time = state->thermal_latest - state->thermal_first;
++found->count;
if (state->opt.fake_device) {
/* fill with fake data */
found->data[0].time = 0;
found->data[0].temperature = 27;
found->data[1].time = 100;
found->data[1].temperature = 28;
found->data[2].time = 300;
found->data[2].temperature = 29;
found->data[3].time = 700;
found->data[3].temperature = 30;
found->data[4].time = 1500;
found->data[4].temperature = 31;
found->count = 5;
}
/* log the new data */
log_tag("thermal:heat:%s:%" PRIu64 ":%u:", devinfo->name, devinfo->device, found->count);
for (k = 0; k < found->count; ++k)
log_tag("%s%d/%d", k > 0 ? "," : "", (int)found->data[k].temperature, (int)found->data[k].time);
log_tag("\n");
/* estimate parameters */
found->params = fit_thermal_model(found->data, found->count, state->thermal_ambient_temperature);
log_tag("thermal:params:%s:%" PRIu64 ":%g:%g:%g:%g:%g:%g\n", devinfo->name, devinfo->device,
found->params.k_heat, found->params.t_ambient, found->params.t_steady,
found->params.rmse, found->params.r_squared, found->params.max_error);
}
/* if no valid temperature was collected, report failure */
if (count == 0)
goto bail_error;
/* always update the highest temperature */
state->thermal_highest_temperature = highest_temperature;
log_tag("thermal:highest:%d\n", highest_temperature);
log_flush();
tommy_list_foreach(&high, free);
tommy_list_foreach(&low, free);
return 0;
bail_error:
tommy_list_foreach(&high, free);
tommy_list_foreach(&low, free);
return -1;
}
int state_thermal_alarm(struct snapraid_state* state)
{
/* if no limit, there is no thermal support */
if (state->thermal_temperature_limit == 0)
return 0;
if (state->thermal_highest_temperature <= state->thermal_temperature_limit)
return 0;
return 1;
}
void state_thermal_cooldown(struct snapraid_state* state)
{
int cooldown_time = state->thermal_cooldown_time;
if (cooldown_time == 0)
cooldown_time = 5 * 60; /* default sleep time */
if (cooldown_time < 3 * 60)
cooldown_time = 3 * 60; /* minimum sleep time */
/* from now on, stop any further data gathering as the heating is interrupted */
state->thermal_stop_gathering = 1;
for (;;) {
int sleep_time = cooldown_time;
log_tag("thermal:spindown\n");
/*
* Power management is best effort.
*
* Some devices may not support explicit spindown/spinup operations, or an
* operation may fail only for a subset of the devices. This must not make the
* whole thermal cooldown fail.
*
* Thermal safety is enforced by measuring the temperatures again after the
* cooldown. If any disk is still above the configured limit, the cooldown is
* repeated. Therefore failure to spin down a device only makes cooling less
* effective; it does not allow the operation to resume while a measurable disk
* is still above the temperature limit.
*/
state_device_force(state, DEVICE_DOWN, 0, 1);
msg_progress("Cooldown...\n");
log_tag("thermal:cooldown:%d\n", sleep_time);
printf("Waiting for %d minutes...\n", sleep_time / 60);
log_flush();
/* every 30 seconds spin down any disk that was spunup */
while (sleep_time > 0 && !os_signal_interrupt()) {
state_device_force(state, DEVICE_DOWNIFUP, 0, 1);
sleep(30);
sleep_time -= 30;
}
if (os_signal_interrupt())
break; /* don't wake-up if we are interrupting */
log_tag("thermal:spinup\n");
/* spinup */
state_device(state, DEVICE_UP, 0);
/* log new thermal info */
if (state_thermal(state, time(0)) != 0)
break;
/* repeat the cooldown if the temperature is still outside the operating range */
if (!state_thermal_alarm(state))
break;
}
}
int state_thermal_begin(struct snapraid_state* state, time_t now)
{
if (state->thermal_temperature_limit == 0)
return 1;
/* initial thermal measure */
state->thermal_first = os_tick_sec();
state->thermal_latest = state->thermal_first;
state_thermal(state, now);
if (state->thermal_system_temperature != 0) {
printf("System temperature is %u degrees\n", state->thermal_system_temperature);
if (state->thermal_temperature_limit != 0 && state->thermal_temperature_limit <= state->thermal_system_temperature) {
/* LCOV_EXCL_START */
log_fatal(EENVIRONMENT, "DANGER! System temperature of %d degrees is higher than the temperature limit of %d degrees. Unable to proceed!\n", state->thermal_system_temperature, state->thermal_temperature_limit);
log_flush();
return 0;
/* LCOV_EXCL_STOP */
}
}
if (state_thermal_alarm(state)) {
msg_progress("Hard disk temperature of %d degrees is already outside the operating range. Cooling down before starting...\n", state->thermal_highest_temperature);
state_thermal_cooldown(state);
}
return 1;
}

View file

@ -1,62 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2025 Andrea Mazzoleni
#ifndef THERMAL_H
#define THERMAL_H
#include "elem.h"
/****************************************************************************/
/* thermal */
/**
* Period of temperature measures
*/
#define THERMAL_PERIOD_SECONDS 30
/**
* Max number of temperature measures
*/
#define THERMAL_MAX 100
/**
* Minimum value of the R^2 to consider valid a measure
*/
#define THERMAL_R_SQUARED_LIMIT 0.9
struct snapraid_thermal_point {
double temperature; /**< Temperatures in celsius */
double time; /**< Time in seconds */
};
struct snapraid_thermal_params {
double k_heat; /**< Heating coefficient */
double t_steady; /**< Steady state temperature during heating */
double t_ambient; /**< Ambient temperature */
double rmse; /**< Root mean square error of the fit */
double r_squared; /**< Coefficient of determination */
double max_error; /**< Maximum absolute error in fit */
};
struct snapraid_thermal {
uint64_t device; /**< Device ID. */
char name[PATH_MAX]; /**< Name of the disk. Note that it's not unique as more physical disks may map to the same logical disk */
int latest_temperature; /**< Latest temperature */
struct snapraid_thermal_point data[THERMAL_MAX]; /**< Measures. Stopped after the first sleep. */
unsigned count; /**< Number of measures */
struct snapraid_thermal_params params; /**< Estimated thermal parameters */
tommy_node node; /**< Next node in the list. */
};
/**
* Allocate a thermal state.
*/
struct snapraid_thermal* thermal_alloc(uint64_t dev, const char* name);
/**
* Deallocate a thermal state.
*/
void thermal_free(void* void_thermal);
#endif

View file

@ -1,198 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2014 Andrea Mazzoleni
#include "os/portable.h"
#include "support.h"
#include "elem.h"
#include "state.h"
#include "handle.h"
int state_touch(struct snapraid_state* state)
{
tommy_node* i;
unsigned counter = 0;
int error = 0;
msg_progress("Setting sub-second timestamps...\n");
/* for all disks */
for (i = state->disklist; i != 0; i = i->next) {
struct snapraid_disk* disk = i->data;
tommy_node* j;
/* for all files */
for (j = disk->filelist; j != 0; j = j->next) {
struct snapraid_file* file = j->data;
/*
* If the file has a zero nanosecond timestamp
* note that symbolic links are not in the file list
* and then are not processed
*/
if (file->mtime_nsec == 0) {
char path[PATH_MAX];
struct stat st;
int f;
int ret;
int nsec;
int flags;
pathprint(path, sizeof(path), "%s%s", disk->dir, file->sub);
/* set a new nanosecond timestamp different than 0 */
do {
uint32_t nano;
/* get a random nanosecond value */
if (os_randomize(&nano, sizeof(nano)) != 0) {
/* LCOV_EXCL_START */
log_fatal(errno, "Failed to retrieve random values.\n");
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
nsec = nano % 1000000000;
} while (nsec == 0);
/*
* O_BINARY: open as binary file (Windows only)
* O_NOFOLLOW: do not follow links to ensure to open the real file
*/
flags = O_BINARY | O_NOFOLLOW;
#ifdef _WIN32
/* in Windows we must have write access at the file */
flags |= O_RDWR;
#else
/* in all others platforms, read access is enough */
flags |= O_RDONLY;
#endif
/* open it */
f = open(path, flags);
#ifdef _WIN32
if (f == -1) {
/* LCOV_EXCL_START */
if (errno == EACCES) {
int attributes = windows_get_file_attributes(path);
if (attributes != -1 && (attributes & FILE_ATTRIBUTE_READONLY) != 0) {
/* remove read only attribute */
if (windows_set_file_attributes(path, attributes & ~FILE_ATTRIBUTE_READONLY) == 0) {
f = open(path, flags);
if (windows_set_file_attributes(path, attributes) != 0) {
log_error(errno, "Error restoring read-only attribute for '%s'. %s.\n", path, strerror(errno));
++error;
}
}
}
}
/* LCOV_EXCL_STOP */
}
#endif
if (f == -1) {
/*
* Ignore missing files because they may have been deleted
* or moved since the last sync. Also ignore symbolic links
* which fail with ELOOP due to O_NOFOLLOW.
*/
if (errno == ENOENT || errno == ENOTDIR || errno == ELOOP)
continue;
/* LCOV_EXCL_START */
log_error(errno, "Error opening file '%s'. %s.\n", path, strerror(errno));
++error;
continue;
/* LCOV_EXCL_STOP */
}
/*
* Get the present timestamp, that may be different than the one
* in the content file
*/
ret = fstat(f, &st);
if (ret == -1) {
/* LCOV_EXCL_START */
close(f);
log_error(errno, "Error accessing file '%s'. %s.\n", path, strerror(errno));
++error;
continue;
/* LCOV_EXCL_STOP */
}
/*
* Touch only regular files that are still unchanged compared to
* the content file. Otherwise changing the timestamp here
* could hide a modification from the following scan.
*/
if (!S_ISREG(st.st_mode)
|| st.st_size != file->size
|| st.st_mtime != file->mtime_sec
|| STAT_NSEC(&st) != file->mtime_nsec
) {
close(f);
continue;
}
/* set the tweaked modification time, with new nano seconds */
ret = fmtime(f, st.st_mtime, nsec);
if (ret != 0) {
/* LCOV_EXCL_START */
close(f);
log_error(errno, "Error timing file '%s'. %s.\n", path, strerror(errno));
++error;
continue;
/* LCOV_EXCL_STOP */
}
/*
* Uses fstat again to get the present timestamp
* this is needed because the value read
* may be different than the written one
*/
ret = fstat(f, &st);
if (ret == -1) {
/* LCOV_EXCL_START */
close(f);
log_error(errno, "Error accessing file '%s'. %s.\n", path, strerror(errno));
++error;
continue;
/* LCOV_EXCL_STOP */
}
/* close it */
ret = close(f);
if (ret != 0) {
/* LCOV_EXCL_START */
log_error(errno, "Error closing file '%s'. %s.\n", path, strerror(errno));
++error;
continue;
/* LCOV_EXCL_STOP */
}
/*
* Set the same nanosecond value in the content file
* note that if the seconds value is already matching
* the file won't be synced because the content file will
* contain the new updated timestamp
*/
file->mtime_nsec = STAT_NSEC(&st);
/* state changed, we need to update it */
state->need_write = 1;
log_tag("touch:%s:%s: %" PRIu64 ".%d\n", disk->name, esc_tag(file->sub), (uint64_t)st.st_mtime, STAT_NSEC(&st));
msg_info("touch %s\n", fmt_term(disk, file->sub));
++counter;
}
}
}
msg_status("\n");
msg_status("%8u touched files\n", counter);
if (error != 0)
return -1;
return 0;
}

File diff suppressed because it is too large Load diff

View file

@ -1,886 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
#include "os/portable.h"
#include "support.h"
#include "util.h"
#include "raid/cpu.h"
#include "raid/memory.h"
#include "tommyds/tommyhash.h"
/****************************************************************************/
/* memory */
void* malloc_nofail_align(size_t size, void** freeptr)
{
void* ptr;
ptr = raid_malloc(size, freeptr);
if (!ptr) {
/* LCOV_EXCL_START */
malloc_fail(size);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
return ptr;
}
void* malloc_nofail_direct(size_t size, void** freeptr)
{
void* ptr;
ptr = raid_malloc_align(size, direct_size(), freeptr);
if (!ptr) {
/* LCOV_EXCL_START */
malloc_fail(size);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
return ptr;
}
void** malloc_nofail_vector_align(int n, size_t size, void** freeptr)
{
void* ptr;
ptr = raid_malloc_vector(n, size, freeptr);
if (!ptr) {
/* LCOV_EXCL_START */
malloc_fail(n * size);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
return ptr;
}
void** malloc_nofail_vector_direct(int n, size_t size, void** freeptr)
{
void* ptr;
ptr = raid_malloc_vector_align(n, size, direct_size(), 0, 0, freeptr);
if (!ptr) {
/* LCOV_EXCL_START */
malloc_fail(n * size);
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
return ptr;
}
void mtest_vector(int n, size_t size, void** vv)
{
if (raid_mtest_vector(n, size, vv) != 0) {
/* LCOV_EXCL_START */
log_fatal(EINTERNAL, "DANGER! Your RAM memory is broken! DO NOT PROCEED UNTIL FIXED!\n");
log_fatal(EINTERNAL, "Try running a memory test like http://www.memtest86.com/\n");
exit(EXIT_FAILURE);
/* LCOV_EXCL_STOP */
}
}
/****************************************************************************/
/* crc */
uint32_t CRC32C_0[256] = {
0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4,
0xc79a971f, 0x35f1141c, 0x26a1e7e8, 0xd4ca64eb,
0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,
0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24,
0x105ec76f, 0xe235446c, 0xf165b798, 0x030e349b,
0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,
0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54,
0x5d1d08bf, 0xaf768bbc, 0xbc267848, 0x4e4dfb4b,
0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,
0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35,
0xaa64d611, 0x580f5512, 0x4b5fa6e6, 0xb93425e5,
0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,
0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45,
0xf779deae, 0x05125dad, 0x1642ae59, 0xe4292d5a,
0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,
0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595,
0x417b1dbc, 0xb3109ebf, 0xa0406d4b, 0x522bee48,
0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,
0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687,
0x0c38d26c, 0xfe53516f, 0xed03a29b, 0x1f682198,
0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,
0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38,
0xdbfc821c, 0x2997011f, 0x3ac7f2eb, 0xc8ac71e8,
0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,
0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096,
0xa65c047d, 0x5437877e, 0x4767748a, 0xb50cf789,
0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,
0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46,
0x7198540d, 0x83f3d70e, 0x90a324fa, 0x62c8a7f9,
0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,
0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36,
0x3cdb9bdd, 0xceb018de, 0xdde0eb2a, 0x2f8b6829,
0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,
0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93,
0x082f63b7, 0xfa44e0b4, 0xe9141340, 0x1b7f9043,
0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,
0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3,
0x55326b08, 0xa759e80b, 0xb4091bff, 0x466298fc,
0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,
0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033,
0xa24bb5a6, 0x502036a5, 0x4370c551, 0xb11b4652,
0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,
0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d,
0xef087a76, 0x1d63f975, 0x0e330a81, 0xfc588982,
0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,
0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622,
0x38cc2a06, 0xcaa7a905, 0xd9f75af1, 0x2b9cd9f2,
0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,
0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530,
0x0417b1db, 0xf67c32d8, 0xe52cc12c, 0x1747422f,
0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,
0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0,
0xd3d3e1ab, 0x21b862a8, 0x32e8915c, 0xc083125f,
0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,
0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90,
0x9e902e7b, 0x6cfbad78, 0x7fab5e8c, 0x8dc0dd8f,
0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,
0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1,
0x69e9f0d5, 0x9b8273d6, 0x88d28022, 0x7ab90321,
0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,
0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81,
0x34f4f86a, 0xc69f7b69, 0xd5cf889d, 0x27a40b9e,
0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,
0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351
};
uint32_t CRC32C_1[256] = {
0x00000000, 0x13a29877, 0x274530ee, 0x34e7a899,
0x4e8a61dc, 0x5d28f9ab, 0x69cf5132, 0x7a6dc945,
0x9d14c3b8, 0x8eb65bcf, 0xba51f356, 0xa9f36b21,
0xd39ea264, 0xc03c3a13, 0xf4db928a, 0xe7790afd,
0x3fc5f181, 0x2c6769f6, 0x1880c16f, 0x0b225918,
0x714f905d, 0x62ed082a, 0x560aa0b3, 0x45a838c4,
0xa2d13239, 0xb173aa4e, 0x859402d7, 0x96369aa0,
0xec5b53e5, 0xfff9cb92, 0xcb1e630b, 0xd8bcfb7c,
0x7f8be302, 0x6c297b75, 0x58ced3ec, 0x4b6c4b9b,
0x310182de, 0x22a31aa9, 0x1644b230, 0x05e62a47,
0xe29f20ba, 0xf13db8cd, 0xc5da1054, 0xd6788823,
0xac154166, 0xbfb7d911, 0x8b507188, 0x98f2e9ff,
0x404e1283, 0x53ec8af4, 0x670b226d, 0x74a9ba1a,
0x0ec4735f, 0x1d66eb28, 0x298143b1, 0x3a23dbc6,
0xdd5ad13b, 0xcef8494c, 0xfa1fe1d5, 0xe9bd79a2,
0x93d0b0e7, 0x80722890, 0xb4958009, 0xa737187e,
0xff17c604, 0xecb55e73, 0xd852f6ea, 0xcbf06e9d,
0xb19da7d8, 0xa23f3faf, 0x96d89736, 0x857a0f41,
0x620305bc, 0x71a19dcb, 0x45463552, 0x56e4ad25,
0x2c896460, 0x3f2bfc17, 0x0bcc548e, 0x186eccf9,
0xc0d23785, 0xd370aff2, 0xe797076b, 0xf4359f1c,
0x8e585659, 0x9dface2e, 0xa91d66b7, 0xbabffec0,
0x5dc6f43d, 0x4e646c4a, 0x7a83c4d3, 0x69215ca4,
0x134c95e1, 0x00ee0d96, 0x3409a50f, 0x27ab3d78,
0x809c2506, 0x933ebd71, 0xa7d915e8, 0xb47b8d9f,
0xce1644da, 0xddb4dcad, 0xe9537434, 0xfaf1ec43,
0x1d88e6be, 0x0e2a7ec9, 0x3acdd650, 0x296f4e27,
0x53028762, 0x40a01f15, 0x7447b78c, 0x67e52ffb,
0xbf59d487, 0xacfb4cf0, 0x981ce469, 0x8bbe7c1e,
0xf1d3b55b, 0xe2712d2c, 0xd69685b5, 0xc5341dc2,
0x224d173f, 0x31ef8f48, 0x050827d1, 0x16aabfa6,
0x6cc776e3, 0x7f65ee94, 0x4b82460d, 0x5820de7a,
0xfbc3faf9, 0xe861628e, 0xdc86ca17, 0xcf245260,
0xb5499b25, 0xa6eb0352, 0x920cabcb, 0x81ae33bc,
0x66d73941, 0x7575a136, 0x419209af, 0x523091d8,
0x285d589d, 0x3bffc0ea, 0x0f186873, 0x1cbaf004,
0xc4060b78, 0xd7a4930f, 0xe3433b96, 0xf0e1a3e1,
0x8a8c6aa4, 0x992ef2d3, 0xadc95a4a, 0xbe6bc23d,
0x5912c8c0, 0x4ab050b7, 0x7e57f82e, 0x6df56059,
0x1798a91c, 0x043a316b, 0x30dd99f2, 0x237f0185,
0x844819fb, 0x97ea818c, 0xa30d2915, 0xb0afb162,
0xcac27827, 0xd960e050, 0xed8748c9, 0xfe25d0be,
0x195cda43, 0x0afe4234, 0x3e19eaad, 0x2dbb72da,
0x57d6bb9f, 0x447423e8, 0x70938b71, 0x63311306,
0xbb8de87a, 0xa82f700d, 0x9cc8d894, 0x8f6a40e3,
0xf50789a6, 0xe6a511d1, 0xd242b948, 0xc1e0213f,
0x26992bc2, 0x353bb3b5, 0x01dc1b2c, 0x127e835b,
0x68134a1e, 0x7bb1d269, 0x4f567af0, 0x5cf4e287,
0x04d43cfd, 0x1776a48a, 0x23910c13, 0x30339464,
0x4a5e5d21, 0x59fcc556, 0x6d1b6dcf, 0x7eb9f5b8,
0x99c0ff45, 0x8a626732, 0xbe85cfab, 0xad2757dc,
0xd74a9e99, 0xc4e806ee, 0xf00fae77, 0xe3ad3600,
0x3b11cd7c, 0x28b3550b, 0x1c54fd92, 0x0ff665e5,
0x759baca0, 0x663934d7, 0x52de9c4e, 0x417c0439,
0xa6050ec4, 0xb5a796b3, 0x81403e2a, 0x92e2a65d,
0xe88f6f18, 0xfb2df76f, 0xcfca5ff6, 0xdc68c781,
0x7b5fdfff, 0x68fd4788, 0x5c1aef11, 0x4fb87766,
0x35d5be23, 0x26772654, 0x12908ecd, 0x013216ba,
0xe64b1c47, 0xf5e98430, 0xc10e2ca9, 0xd2acb4de,
0xa8c17d9b, 0xbb63e5ec, 0x8f844d75, 0x9c26d502,
0x449a2e7e, 0x5738b609, 0x63df1e90, 0x707d86e7,
0x0a104fa2, 0x19b2d7d5, 0x2d557f4c, 0x3ef7e73b,
0xd98eedc6, 0xca2c75b1, 0xfecbdd28, 0xed69455f,
0x97048c1a, 0x84a6146d, 0xb041bcf4, 0xa3e32483
};
uint32_t CRC32C_2[256] = {
0x00000000, 0xa541927e, 0x4f6f520d, 0xea2ec073,
0x9edea41a, 0x3b9f3664, 0xd1b1f617, 0x74f06469,
0x38513ec5, 0x9d10acbb, 0x773e6cc8, 0xd27ffeb6,
0xa68f9adf, 0x03ce08a1, 0xe9e0c8d2, 0x4ca15aac,
0x70a27d8a, 0xd5e3eff4, 0x3fcd2f87, 0x9a8cbdf9,
0xee7cd990, 0x4b3d4bee, 0xa1138b9d, 0x045219e3,
0x48f3434f, 0xedb2d131, 0x079c1142, 0xa2dd833c,
0xd62de755, 0x736c752b, 0x9942b558, 0x3c032726,
0xe144fb14, 0x4405696a, 0xae2ba919, 0x0b6a3b67,
0x7f9a5f0e, 0xdadbcd70, 0x30f50d03, 0x95b49f7d,
0xd915c5d1, 0x7c5457af, 0x967a97dc, 0x333b05a2,
0x47cb61cb, 0xe28af3b5, 0x08a433c6, 0xade5a1b8,
0x91e6869e, 0x34a714e0, 0xde89d493, 0x7bc846ed,
0x0f382284, 0xaa79b0fa, 0x40577089, 0xe516e2f7,
0xa9b7b85b, 0x0cf62a25, 0xe6d8ea56, 0x43997828,
0x37691c41, 0x92288e3f, 0x78064e4c, 0xdd47dc32,
0xc76580d9, 0x622412a7, 0x880ad2d4, 0x2d4b40aa,
0x59bb24c3, 0xfcfab6bd, 0x16d476ce, 0xb395e4b0,
0xff34be1c, 0x5a752c62, 0xb05bec11, 0x151a7e6f,
0x61ea1a06, 0xc4ab8878, 0x2e85480b, 0x8bc4da75,
0xb7c7fd53, 0x12866f2d, 0xf8a8af5e, 0x5de93d20,
0x29195949, 0x8c58cb37, 0x66760b44, 0xc337993a,
0x8f96c396, 0x2ad751e8, 0xc0f9919b, 0x65b803e5,
0x1148678c, 0xb409f5f2, 0x5e273581, 0xfb66a7ff,
0x26217bcd, 0x8360e9b3, 0x694e29c0, 0xcc0fbbbe,
0xb8ffdfd7, 0x1dbe4da9, 0xf7908dda, 0x52d11fa4,
0x1e704508, 0xbb31d776, 0x511f1705, 0xf45e857b,
0x80aee112, 0x25ef736c, 0xcfc1b31f, 0x6a802161,
0x56830647, 0xf3c29439, 0x19ec544a, 0xbcadc634,
0xc85da25d, 0x6d1c3023, 0x8732f050, 0x2273622e,
0x6ed23882, 0xcb93aafc, 0x21bd6a8f, 0x84fcf8f1,
0xf00c9c98, 0x554d0ee6, 0xbf63ce95, 0x1a225ceb,
0x8b277743, 0x2e66e53d, 0xc448254e, 0x6109b730,
0x15f9d359, 0xb0b84127, 0x5a968154, 0xffd7132a,
0xb3764986, 0x1637dbf8, 0xfc191b8b, 0x595889f5,
0x2da8ed9c, 0x88e97fe2, 0x62c7bf91, 0xc7862def,
0xfb850ac9, 0x5ec498b7, 0xb4ea58c4, 0x11abcaba,
0x655baed3, 0xc01a3cad, 0x2a34fcde, 0x8f756ea0,
0xc3d4340c, 0x6695a672, 0x8cbb6601, 0x29faf47f,
0x5d0a9016, 0xf84b0268, 0x1265c21b, 0xb7245065,
0x6a638c57, 0xcf221e29, 0x250cde5a, 0x804d4c24,
0xf4bd284d, 0x51fcba33, 0xbbd27a40, 0x1e93e83e,
0x5232b292, 0xf77320ec, 0x1d5de09f, 0xb81c72e1,
0xccec1688, 0x69ad84f6, 0x83834485, 0x26c2d6fb,
0x1ac1f1dd, 0xbf8063a3, 0x55aea3d0, 0xf0ef31ae,
0x841f55c7, 0x215ec7b9, 0xcb7007ca, 0x6e3195b4,
0x2290cf18, 0x87d15d66, 0x6dff9d15, 0xc8be0f6b,
0xbc4e6b02, 0x190ff97c, 0xf321390f, 0x5660ab71,
0x4c42f79a, 0xe90365e4, 0x032da597, 0xa66c37e9,
0xd29c5380, 0x77ddc1fe, 0x9df3018d, 0x38b293f3,
0x7413c95f, 0xd1525b21, 0x3b7c9b52, 0x9e3d092c,
0xeacd6d45, 0x4f8cff3b, 0xa5a23f48, 0x00e3ad36,
0x3ce08a10, 0x99a1186e, 0x738fd81d, 0xd6ce4a63,
0xa23e2e0a, 0x077fbc74, 0xed517c07, 0x4810ee79,
0x04b1b4d5, 0xa1f026ab, 0x4bdee6d8, 0xee9f74a6,
0x9a6f10cf, 0x3f2e82b1, 0xd50042c2, 0x7041d0bc,
0xad060c8e, 0x08479ef0, 0xe2695e83, 0x4728ccfd,
0x33d8a894, 0x96993aea, 0x7cb7fa99, 0xd9f668e7,
0x9557324b, 0x3016a035, 0xda386046, 0x7f79f238,
0x0b899651, 0xaec8042f, 0x44e6c45c, 0xe1a75622,
0xdda47104, 0x78e5e37a, 0x92cb2309, 0x378ab177,
0x437ad51e, 0xe63b4760, 0x0c158713, 0xa954156d,
0xe5f54fc1, 0x40b4ddbf, 0xaa9a1dcc, 0x0fdb8fb2,
0x7b2bebdb, 0xde6a79a5, 0x3444b9d6, 0x91052ba8
};
uint32_t CRC32C_3[256] = {
0x00000000, 0xdd45aab8, 0xbf672381, 0x62228939,
0x7b2231f3, 0xa6679b4b, 0xc4451272, 0x1900b8ca,
0xf64463e6, 0x2b01c95e, 0x49234067, 0x9466eadf,
0x8d665215, 0x5023f8ad, 0x32017194, 0xef44db2c,
0xe964b13d, 0x34211b85, 0x560392bc, 0x8b463804,
0x924680ce, 0x4f032a76, 0x2d21a34f, 0xf06409f7,
0x1f20d2db, 0xc2657863, 0xa047f15a, 0x7d025be2,
0x6402e328, 0xb9474990, 0xdb65c0a9, 0x06206a11,
0xd725148b, 0x0a60be33, 0x6842370a, 0xb5079db2,
0xac072578, 0x71428fc0, 0x136006f9, 0xce25ac41,
0x2161776d, 0xfc24ddd5, 0x9e0654ec, 0x4343fe54,
0x5a43469e, 0x8706ec26, 0xe524651f, 0x3861cfa7,
0x3e41a5b6, 0xe3040f0e, 0x81268637, 0x5c632c8f,
0x45639445, 0x98263efd, 0xfa04b7c4, 0x27411d7c,
0xc805c650, 0x15406ce8, 0x7762e5d1, 0xaa274f69,
0xb327f7a3, 0x6e625d1b, 0x0c40d422, 0xd1057e9a,
0xaba65fe7, 0x76e3f55f, 0x14c17c66, 0xc984d6de,
0xd0846e14, 0x0dc1c4ac, 0x6fe34d95, 0xb2a6e72d,
0x5de23c01, 0x80a796b9, 0xe2851f80, 0x3fc0b538,
0x26c00df2, 0xfb85a74a, 0x99a72e73, 0x44e284cb,
0x42c2eeda, 0x9f874462, 0xfda5cd5b, 0x20e067e3,
0x39e0df29, 0xe4a57591, 0x8687fca8, 0x5bc25610,
0xb4868d3c, 0x69c32784, 0x0be1aebd, 0xd6a40405,
0xcfa4bccf, 0x12e11677, 0x70c39f4e, 0xad8635f6,
0x7c834b6c, 0xa1c6e1d4, 0xc3e468ed, 0x1ea1c255,
0x07a17a9f, 0xdae4d027, 0xb8c6591e, 0x6583f3a6,
0x8ac7288a, 0x57828232, 0x35a00b0b, 0xe8e5a1b3,
0xf1e51979, 0x2ca0b3c1, 0x4e823af8, 0x93c79040,
0x95e7fa51, 0x48a250e9, 0x2a80d9d0, 0xf7c57368,
0xeec5cba2, 0x3380611a, 0x51a2e823, 0x8ce7429b,
0x63a399b7, 0xbee6330f, 0xdcc4ba36, 0x0181108e,
0x1881a844, 0xc5c402fc, 0xa7e68bc5, 0x7aa3217d,
0x52a0c93f, 0x8fe56387, 0xedc7eabe, 0x30824006,
0x2982f8cc, 0xf4c75274, 0x96e5db4d, 0x4ba071f5,
0xa4e4aad9, 0x79a10061, 0x1b838958, 0xc6c623e0,
0xdfc69b2a, 0x02833192, 0x60a1b8ab, 0xbde41213,
0xbbc47802, 0x6681d2ba, 0x04a35b83, 0xd9e6f13b,
0xc0e649f1, 0x1da3e349, 0x7f816a70, 0xa2c4c0c8,
0x4d801be4, 0x90c5b15c, 0xf2e73865, 0x2fa292dd,
0x36a22a17, 0xebe780af, 0x89c50996, 0x5480a32e,
0x8585ddb4, 0x58c0770c, 0x3ae2fe35, 0xe7a7548d,
0xfea7ec47, 0x23e246ff, 0x41c0cfc6, 0x9c85657e,
0x73c1be52, 0xae8414ea, 0xcca69dd3, 0x11e3376b,
0x08e38fa1, 0xd5a62519, 0xb784ac20, 0x6ac10698,
0x6ce16c89, 0xb1a4c631, 0xd3864f08, 0x0ec3e5b0,
0x17c35d7a, 0xca86f7c2, 0xa8a47efb, 0x75e1d443,
0x9aa50f6f, 0x47e0a5d7, 0x25c22cee, 0xf8878656,
0xe1873e9c, 0x3cc29424, 0x5ee01d1d, 0x83a5b7a5,
0xf90696d8, 0x24433c60, 0x4661b559, 0x9b241fe1,
0x8224a72b, 0x5f610d93, 0x3d4384aa, 0xe0062e12,
0x0f42f53e, 0xd2075f86, 0xb025d6bf, 0x6d607c07,
0x7460c4cd, 0xa9256e75, 0xcb07e74c, 0x16424df4,
0x106227e5, 0xcd278d5d, 0xaf050464, 0x7240aedc,
0x6b401616, 0xb605bcae, 0xd4273597, 0x09629f2f,
0xe6264403, 0x3b63eebb, 0x59416782, 0x8404cd3a,
0x9d0475f0, 0x4041df48, 0x22635671, 0xff26fcc9,
0x2e238253, 0xf36628eb, 0x9144a1d2, 0x4c010b6a,
0x5501b3a0, 0x88441918, 0xea669021, 0x37233a99,
0xd867e1b5, 0x05224b0d, 0x6700c234, 0xba45688c,
0xa345d046, 0x7e007afe, 0x1c22f3c7, 0xc167597f,
0xc747336e, 0x1a0299d6, 0x782010ef, 0xa565ba57,
0xbc65029d, 0x6120a825, 0x0302211c, 0xde478ba4,
0x31035088, 0xec46fa30, 0x8e647309, 0x5321d9b1,
0x4a21617b, 0x9764cbc3, 0xf54642fa, 0x2803e842
};
#ifdef CONFIG_X86_64
uint32_t CRC32C_X86_64_SKIP[6][8][16];
#endif
#if CONFIG_ARM_CRC
uint32_t CRC32C_ARM64_SKIP[6][8][16];
#endif
#if defined(CONFIG_X86_64) || CONFIG_ARM_CRC
static uint32_t crc32c_shift_table[sizeof(size_t) * 8][32];
static uint32_t crc32c_matrix_times(const uint32_t* matrix, uint32_t vector)
{
uint32_t value = 0;
while (vector) {
if (vector & 1)
value ^= *matrix;
vector >>= 1;
++matrix;
}
return value;
}
static void crc32c_matrix_square(uint32_t* square, const uint32_t* matrix)
{
unsigned i;
for (i = 0; i < 32; ++i)
square[i] = crc32c_matrix_times(matrix, matrix[i]);
}
static void crc32c_shift_init(void)
{
uint32_t matrix[32];
uint32_t square[32];
uint32_t row;
unsigned i;
/* reflected Castagnoli polynomial, represented as one zero-bit operator. */
matrix[0] = 0x82f63b78;
row = 1;
for (i = 1; i < 32; ++i) {
matrix[i] = row;
row <<= 1;
}
/* square three times to obtain the operator for one zero byte. */
crc32c_matrix_square(square, matrix);
crc32c_matrix_square(matrix, square);
crc32c_matrix_square(crc32c_shift_table[0], matrix);
for (i = 1; i < sizeof(size_t) * 8; ++i)
crc32c_matrix_square(crc32c_shift_table[i], crc32c_shift_table[i - 1]);
}
uint32_t crc32c_shift(uint32_t crc, size_t size)
{
unsigned i = 0;
while (size) {
if (size & 1)
crc = crc32c_matrix_times(crc32c_shift_table[i], crc);
size >>= 1;
++i;
}
return crc;
}
static void crc32c_skip_init(uint32_t table[8][16], size_t size)
{
unsigned i;
unsigned j;
/* collapse each fixed-size shift into eight nibble table lookups. */
for (i = 0; i < 8; ++i) {
for (j = 0; j < 16; ++j)
table[i][j] = crc32c_shift((uint32_t)j << (4 * i), size);
}
}
#endif
uint32_t crc32c_gen(uint32_t crc, const unsigned char* ptr, size_t size)
{
crc ^= CRC_IV;
crc = crc32c_gen_plain(crc, ptr, size);
crc ^= CRC_IV;
return crc;
}
#if CONFIG_X86
__aligned_loops(64)
uint32_t crc32c_x86(uint32_t crc, const unsigned char* ptr, size_t size)
{
crc ^= CRC_IV;
crc = crc32c_x86_plain(crc, ptr, size);
crc ^= CRC_IV;
return crc;
}
#endif
#if CONFIG_ARM_CRC
__aligned_loops(64)
uint32_t crc32c_arm64(uint32_t crc, const unsigned char* ptr, size_t size)
{
crc ^= CRC_IV;
crc = crc32c_arm64_plain(crc, ptr, size);
crc ^= CRC_IV;
return crc;
}
#endif
uint32_t (*crc32c)(uint32_t crc, const unsigned char* ptr, size_t size);
void crc32c_init(void)
{
crc32c = crc32c_gen;
#if CONFIG_X86
if (raid_cpu_has_crc32()) {
#ifdef CONFIG_X86_64
crc32c_shift_init();
crc32c_skip_init(CRC32C_X86_64_SKIP[0], CRC32C_X86_64_BLOCK0_SIZE);
crc32c_skip_init(CRC32C_X86_64_SKIP[1], CRC32C_X86_64_BLOCK1_SIZE);
crc32c_skip_init(CRC32C_X86_64_SKIP[2], CRC32C_X86_64_BLOCK2_SIZE);
crc32c_skip_init(CRC32C_X86_64_SKIP[3], CRC32C_X86_64_BLOCK3_SIZE);
crc32c_skip_init(CRC32C_X86_64_SKIP[4], CRC32C_X86_64_BLOCK4_SIZE);
crc32c_skip_init(CRC32C_X86_64_SKIP[5], CRC32C_X86_64_BLOCK5_SIZE);
#endif
crc32c = crc32c_x86;
}
#endif
#if CONFIG_ARM_CRC
crc32c_shift_init();
crc32c_skip_init(CRC32C_ARM64_SKIP[0], CRC32C_ARM64_BLOCK0_SIZE);
crc32c_skip_init(CRC32C_ARM64_SKIP[1], CRC32C_ARM64_BLOCK1_SIZE);
crc32c_skip_init(CRC32C_ARM64_SKIP[2], CRC32C_ARM64_BLOCK2_SIZE);
crc32c_skip_init(CRC32C_ARM64_SKIP[3], CRC32C_ARM64_BLOCK3_SIZE);
crc32c_skip_init(CRC32C_ARM64_SKIP[4], CRC32C_ARM64_BLOCK4_SIZE);
crc32c_skip_init(CRC32C_ARM64_SKIP[5], CRC32C_ARM64_BLOCK5_SIZE);
crc32c = crc32c_arm64;
#endif
}
/****************************************************************************/
/* byte operations */
/**
* Rotate left.
* In x86/x64/ARM they are optimized with a single assembler instruction.
*/
static inline uint32_t util_rotl32(uint32_t x, unsigned r)
{
return (x << (r & 31)) | (x >> ((-r) & 31));
}
static inline uint64_t util_rotl64(uint64_t x, unsigned r)
{
return (x << (r & 63)) | (x >> ((-r) & 63));
}
/**
* Rotate right.
* In x86/x64/ARM they are optimized with a single assembler instruction.
*/
static inline uint32_t util_rotr32(uint32_t x, unsigned r)
{
return (x >> (r & 31)) | (x << ((-r) & 31));
}
static inline uint64_t util_rotr64(uint64_t x, unsigned r)
{
return (x >> (r & 63)) | (x << ((-r) & 63));
}
/**
* Swap endianness.
* They are needed only if BigEndian.
*/
#if defined(__GNUC__)
#define util_swap32(x) __builtin_bswap32(x)
#define util_swap64(x) __builtin_bswap64(x)
#elif HAVE_BYTESWAP_H
#include <byteswap.h>
#define util_swap32(x) bswap_32(x)
#define util_swap64(x) bswap_64(x)
#else
static inline uint32_t util_swap32(uint32_t v)
{
return (util_rotl32(v, 8) & 0x00ff00ff)
| (util_rotl32(v, 24) & 0xff00ff00);
}
static inline uint64_t util_swap64(uint64_t v)
{
return (util_rotl64(v, 8) & 0x000000ff000000ffULL)
| (util_rotl64(v, 24) & 0x0000ff000000ff00ULL)
| (util_rotl64(v, 40) & 0x00ff000000ff0000ULL)
| (util_rotl64(v, 56) & 0xff000000ff000000ULL);
}
#endif
static inline uint32_t util_read32(const void* ptr)
{
uint32_t v;
memcpy(&v, ptr, sizeof(v));
#if WORDS_BIGENDIAN
v = util_swap32(v);
#endif
return v;
}
static inline uint64_t util_read64(const void* ptr)
{
uint64_t v;
memcpy(&v, ptr, sizeof(v));
#if WORDS_BIGENDIAN
v = util_swap64(v);
#endif
return v;
}
static inline void util_write32(void* ptr, uint32_t v)
{
#if WORDS_BIGENDIAN
v = util_swap32(v);
#endif
memcpy(ptr, &v, sizeof(v));
}
static inline void util_write64(void* ptr, uint64_t v)
{
#if WORDS_BIGENDIAN
v = util_swap64(v);
#endif
memcpy(ptr, &v, sizeof(v));
}
int util_selftest(void)
{
/* rotate left 32-bit */
if (util_rotl32(0x00000001U, 1) != 0x00000002U) return -1;
if (util_rotl32(0x80000000U, 1) != 0x00000001U) return -1;
if (util_rotl32(0x00000001U, 31) != 0x80000000U) return -1;
if (util_rotl32(0x12345678U, 4) != 0x23456781U) return -1;
if (util_rotl32(0x12345678U, 0) != 0x12345678U) return -1;
if (util_rotl32(0x12345678U, 32) != 0x12345678U) return -1;
/* rotate right 32-bit */
if (util_rotr32(0x00000001U, 1) != 0x80000000U) return -1;
if (util_rotr32(0x80000000U, 1) != 0x40000000U) return -1;
if (util_rotr32(0x00000002U, 1) != 0x00000001U) return -1;
if (util_rotr32(0x12345678U, 4) != 0x81234567U) return -1;
if (util_rotr32(0x12345678U, 0) != 0x12345678U) return -1;
if (util_rotr32(0x12345678U, 32) != 0x12345678U) return -1;
/* rotate left 64-bit */
if (util_rotl64(1ULL, 1) != 2ULL) return -1;
if (util_rotl64(1ULL << 63, 1) != 1ULL) return -1;
if (util_rotl64(0x123456789ABCDEF0ULL, 8) != 0x3456789ABCDEF012ULL) return -1;
if (util_rotl64(0x123456789ABCDEF0ULL, 0) != 0x123456789ABCDEF0ULL) return -1;
if (util_rotl64(0x123456789ABCDEF0ULL, 64) != 0x123456789ABCDEF0ULL) return -1;
/* rotate right 64-bit */
if (util_rotr64(1ULL, 1) != (1ULL << 63)) return -1;
if (util_rotr64(2ULL, 1) != 1ULL) return -1;
if (util_rotr64(0x123456789ABCDEF0ULL, 8) != 0xF0123456789ABCDEULL) return -1;
if (util_rotr64(0x123456789ABCDEF0ULL, 0) != 0x123456789ABCDEF0ULL) return -1;
if (util_rotr64(0x123456789ABCDEF0ULL, 64) != 0x123456789ABCDEF0ULL) return -1;
/* tommy_mum tests */
uint64_t a, b;
/* small values */
a = 3; b = 4;
tommy_mum(&a, &b);
if (a != 12 || b != 0) return -1;
/* 1 * anything */
a = 0xFFFFFFFFFFFFFFFFULL; b = 1;
tommy_mum(&a, &b);
if (a != 0xFFFFFFFFFFFFFFFFULL || b != 0) return -1;
/* (2^32) * (2^32) = 2^64 */
a = 1ULL << 32; b = 1ULL << 32;
tommy_mum(&a, &b);
if (a != 0 || b != 1) return -1;
/* max uint64 * max uint64 */
a = 0xFFFFFFFFFFFFFFFFULL; b = 0xFFFFFFFFFFFFFFFFULL;
tommy_mum(&a, &b);
if (a != 1 || b != 0xFFFFFFFFFFFFFFFEULL) return -1;
/* larger random-ish test */
a = 0x0123456789ABCDEFULL;
b = 0xFEDCBA9876543210ULL;
tommy_mum(&a, &b);
if (a != 0x2236D88FE5618CF0ULL || b != 0x121FA00AD77D742ULL) return -1;
return 0;
}
/****************************************************************************/
/* hash */
const char* memhashname(unsigned kind)
{
switch (kind) {
case HASH_MURMUR3 : return "murmur3";
case HASH_SPOOKY2 : return "spooky2";
case HASH_MUSEAIR : return "museair";
}
return 0;
}
unsigned membesthash(void)
{
#ifdef CONFIG_X86
if (sizeof(void*) == 4 && !raid_cpu_has_slowmult())
return HASH_MURMUR3;
else
return HASH_SPOOKY2;
#else
if (sizeof(void*) == 4)
return HASH_MURMUR3;
else
return HASH_SPOOKY2;
#endif
}
#include "murmur3.c"
#include "spooky2.c"
#include "museair.c"
void memhash(unsigned kind, const unsigned char* seed, void* digest, const void* src, size_t size)
{
switch (kind) {
case HASH_MURMUR3 :
MurmurHash3_x86_128(src, size, seed, digest);
break;
case HASH_SPOOKY2 :
SpookyHash128(src, size, seed, digest);
break;
case HASH_MUSEAIR :
MuseAirLoong(src, size, seed, digest);
break;
default :
/* LCOV_EXCL_START */
log_fatal(EINTERNAL, "Internal inconsistency in hash function %u\n", kind);
os_abort();
break;
/* LCOV_EXCL_STOP */
}
}
void memhash_block(unsigned kind, const unsigned char* seed, void* digest, const void* src, size_t logical_size, size_t block_size)
{
assert(logical_size <= block_size);
if (memhash_is_block(kind)) {
/*
* Canonical block hashes define the identity of the complete
* canonical RAID block. The caller must have zero-padded the
* buffer after the logical end of the file block.
*/
memhash(kind, seed, digest, src, block_size);
} else {
/*
* Preserve the historical SnapRAID hash semantics for content
* files using legacy hashes.
*/
memhash(kind, seed, digest, src, logical_size);
}
}
const char* hash_config_name(unsigned kind)
{
switch (kind) {
case HASH_UNDEFINED : return "undefined";
case HASH_MURMUR3 : return "murmur3";
case HASH_SPOOKY2 : return "spooky2";
case HASH_MUSEAIR : return "museair";
default :
/* LCOV_EXCL_START */
return "unknown";
/* LCOV_EXCL_STOP */
}
}
unsigned memdiff(const unsigned char* data1, const unsigned char* data2, size_t size)
{
size_t i;
unsigned count;
count = 0;
for (i = 0; i < size; ++i) {
unsigned j;
unsigned char diff = data1[i] ^ data2[i];
for (j = 0; j < 8; ++j) {
if ((diff & 1) != 0)
++count;
diff >>= 1;
}
}
return count;
}
/****************************************************************************/
/* lock */
#if HAVE_LOCKFILE
int lock_lock(const char* file)
{
#ifdef _WIN32
wchar_t conv_buf[PATH_MAX];
HANDLE h;
if (MultiByteToWideChar(CP_UTF8, 0, file, -1, conv_buf, PATH_MAX) <= 0) {
/* LCOV_EXCL_START */
errno = EACCES;
return -1;
/* LCOV_EXCL_STOP */
}
/* open or create the lock file with zero share mode for exclusive access and delete on close */
h = CreateFileW(conv_buf, GENERIC_READ | GENERIC_WRITE | DELETE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE, 0);
if (h == INVALID_HANDLE_VALUE) {
/* LCOV_EXCL_START */
DWORD err = GetLastError();
if (err == ERROR_SHARING_VIOLATION || err == ERROR_ACCESS_DENIED || err == ERROR_DELETE_PENDING) {
errno = EWOULDBLOCK;
} else {
errno = EACCES;
}
return -1;
/* LCOV_EXCL_STOP */
}
/* Windows HANDLE values are 31-bit indices into per-process handle tables, so casting to int is safe */
return (intptr_t)h;
#else
int f;
f = open(file, O_RDONLY | O_CREAT, 0600);
if (f == -1) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
/* exclusive lock, not blocking */
if (flock(f, LOCK_EX | LOCK_NB) == -1) {
/* LCOV_EXCL_START */
close(f);
return -1;
/* LCOV_EXCL_STOP */
}
return f;
#endif
}
#endif
#if HAVE_LOCKFILE
int lock_unlock(int f)
{
#ifdef _WIN32
if (!CloseHandle((HANDLE)(intptr_t)f)) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
return 0;
#else
/*
* Intentionally don't remove the lock file.
* Removing it just introduces race course with other process
* that could have already opened it.
*/
if (close(f) == -1) {
/* LCOV_EXCL_START */
return -1;
/* LCOV_EXCL_STOP */
}
return 0;
#endif
}
#endif
/****************************************************************************/
/* muldiv */
unsigned muldiv(uint64_t v, uint64_t mul, uint64_t div)
{
if (!div)
return 0;
return (uint32_t)(v * mul / div);
}
unsigned muldiv_upper(uint64_t v, uint64_t mul, uint64_t div)
{
if (!div)
return 0;
return (uint32_t)((v * mul + div - 1) / div);
}

View file

@ -1,532 +0,0 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Copyright (C) 2011 Andrea Mazzoleni
#ifndef UTIL_H
#define UTIL_H
#include "tommyds/tommytypes.h"
/****************************************************************************/
/* memory */
/**
* Safe aligned malloc.
* If no memory is available, it aborts.
*/
void* malloc_nofail_align(size_t size, void** freeptr);
/**
* Safe aligned malloc. Usable for direct io.
*/
void* malloc_nofail_direct(size_t size, void** freeptr);
/**
* Safe aligned vector allocation.
* If no memory is available, it aborts.
*/
void** malloc_nofail_vector_align(int n, size_t size, void** freeptr);
/**
* Safe page vector allocation. Usable for direct io.
* If no memory is available, it aborts.
*/
void** malloc_nofail_vector_direct(int n, size_t size, void** freeptr);
/**
* Test the memory vector for RAM problems.
* If a problem is found, it crashes.
*/
void mtest_vector(int n, size_t size, void** vv);
/**
* Compare memory against a repeated byte value.
*
* Return <0 if ptr is less than value, 0 if equal, >0 if greater.
*/
static __always_inline int membcmp(const void* ptr, uint8_t value, size_t size)
{
const uint8_t* p = ptr;
if (size == 0)
return 0;
if (p[0] != value)
return (int)p[0] - (int)value;
/*
* If the buffer contains value up to index k-1, then at offset k-1
* memcmp compares (p + 1)[k - 1] = p[k] against p[k - 1] = value.
* The first differing adjacent pair yields the exact sign (p[k] - value).
*/
return memcmp(p + 1, p, size - 1);
}
/****************************************************************************/
/* crc */
/**
* CRC initial value.
* Using a not zero value allows to detect a leading run of zeros.
*/
#define CRC_IV 0xffffffffU
/**
* CRC-32 (Castagnoli) table.
*/
extern uint32_t CRC32C_0[256];
extern uint32_t CRC32C_1[256];
extern uint32_t CRC32C_2[256];
extern uint32_t CRC32C_3[256];
#define CRC32C_X86_64_BLOCK0_SIZE 5456
#define CRC32C_X86_64_BLOCK1_SIZE 2720
#define CRC32C_X86_64_BLOCK2_SIZE 1360
#define CRC32C_X86_64_BLOCK3_SIZE 672
#define CRC32C_X86_64_BLOCK4_SIZE 336
#define CRC32C_X86_64_BLOCK5_SIZE 160
#ifdef CONFIG_X86_64
extern uint32_t CRC32C_X86_64_SKIP[6][8][16];
#endif
#define CRC32C_ARM64_BLOCK0_SIZE 8192
#define CRC32C_ARM64_BLOCK1_SIZE 4096
#define CRC32C_ARM64_BLOCK2_SIZE 2048
#define CRC32C_ARM64_BLOCK3_SIZE 1024
#define CRC32C_ARM64_BLOCK4_SIZE 512
#define CRC32C_ARM64_BLOCK5_SIZE 256
#if CONFIG_ARM_CRC
extern uint32_t CRC32C_ARM64_SKIP[6][8][16];
#endif
/**
* Advance a raw CRC-32C by a number of zero bytes.
* Used to combine independent hardware CRC lanes.
*/
#if defined(CONFIG_X86_64) || CONFIG_ARM_CRC
uint32_t crc32c_shift(uint32_t crc, size_t size);
#endif
/**
* Compute the CRC-32 (Castagnoli) without the IV.
*/
static inline uint32_t crc32c_gen_plain(uint32_t crc, const unsigned char* ptr, size_t size)
{
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC unroll 1
#elif defined(__clang__)
#pragma unroll 1
#endif
while (size >= 4) {
crc ^= ptr[0] | (uint32_t)ptr[1] << 8 | (uint32_t)ptr[2] << 16 | (uint32_t)ptr[3] << 24;
crc = CRC32C_3[crc & 0xff] ^ CRC32C_2[(crc >> 8) & 0xff] ^ CRC32C_1[(crc >> 16) & 0xff] ^ CRC32C_0[crc >> 24];
ptr += 4;
size -= 4;
}
while (size) {
crc = CRC32C_0[(crc ^ *ptr) & 0xff] ^ (crc >> 8);
++ptr;
--size;
}
return crc;
}
/**
* Compute the CRC-32 (Castagnoli) without the IV.
*/
#if CONFIG_X86
#ifdef CONFIG_X86_64
static __always_inline uint32_t crc32c_x86_64_skip(uint32_t crc, const uint32_t table[8][16])
{
return table[0][crc & 0xf]
^ table[1][(crc >> 4) & 0xf]
^ table[2][(crc >> 8) & 0xf]
^ table[3][(crc >> 12) & 0xf]
^ table[4][(crc >> 16) & 0xf]
^ table[5][(crc >> 20) & 0xf]
^ table[6][(crc >> 24) & 0xf]
^ table[7][crc >> 28];
}
__aligned_loops(64)
static __always_inline uint32_t crc32c_x86_64_3lane(uint32_t crc, const unsigned char* ptr, size_t lane_size, const uint32_t table[8][16])
{
const unsigned char* ptr0 = ptr;
const unsigned char* ptr1 = ptr + lane_size;
const unsigned char* ptr2 = ptr1 + lane_size;
const unsigned char* end = ptr1;
uint64_t crc0 = crc;
uint64_t crc1 = 0;
uint64_t crc2 = 0;
/*
* Keep three dependency chains in flight to hide the CRC32 latency.
* Lane sizes are multiples of 16 to avoid a separate tail loop.
*/
while (ptr0 < end) {
asm volatile ("crc32q %1, %0\n" : "+r" (crc0) : "m" (*(const uint64_t*)ptr0));
asm volatile ("crc32q %1, %0\n" : "+r" (crc1) : "m" (*(const uint64_t*)ptr1));
asm volatile ("crc32q %1, %0\n" : "+r" (crc2) : "m" (*(const uint64_t*)ptr2));
asm volatile ("crc32q %1, %0\n" : "+r" (crc0) : "m" (*(const uint64_t*)(ptr0 + 8)));
asm volatile ("crc32q %1, %0\n" : "+r" (crc1) : "m" (*(const uint64_t*)(ptr1 + 8)));
asm volatile ("crc32q %1, %0\n" : "+r" (crc2) : "m" (*(const uint64_t*)(ptr2 + 8)));
ptr0 += 16;
ptr1 += 16;
ptr2 += 16;
}
crc = crc32c_x86_64_skip((uint32_t)crc0, table) ^ (uint32_t)crc1;
return crc32c_x86_64_skip(crc, table) ^ (uint32_t)crc2;
}
#endif
__aligned_loops(64)
static __always_inline uint32_t crc32c_x86_plain(uint32_t crc, const unsigned char* ptr, size_t size)
{
#ifdef CONFIG_X86_64
uint64_t crc64 = crc;
if (size >= 3 * CRC32C_X86_64_BLOCK5_SIZE) {
while (size >= 3 * CRC32C_X86_64_BLOCK0_SIZE) {
crc64 = crc32c_x86_64_3lane((uint32_t)crc64, ptr, CRC32C_X86_64_BLOCK0_SIZE, CRC32C_X86_64_SKIP[0]);
ptr += 3 * CRC32C_X86_64_BLOCK0_SIZE;
size -= 3 * CRC32C_X86_64_BLOCK0_SIZE;
}
while (size >= 3 * CRC32C_X86_64_BLOCK1_SIZE) {
crc64 = crc32c_x86_64_3lane((uint32_t)crc64, ptr, CRC32C_X86_64_BLOCK1_SIZE, CRC32C_X86_64_SKIP[1]);
ptr += 3 * CRC32C_X86_64_BLOCK1_SIZE;
size -= 3 * CRC32C_X86_64_BLOCK1_SIZE;
}
while (size >= 3 * CRC32C_X86_64_BLOCK2_SIZE) {
crc64 = crc32c_x86_64_3lane((uint32_t)crc64, ptr, CRC32C_X86_64_BLOCK2_SIZE, CRC32C_X86_64_SKIP[2]);
ptr += 3 * CRC32C_X86_64_BLOCK2_SIZE;
size -= 3 * CRC32C_X86_64_BLOCK2_SIZE;
}
while (size >= 3 * CRC32C_X86_64_BLOCK3_SIZE) {
crc64 = crc32c_x86_64_3lane((uint32_t)crc64, ptr, CRC32C_X86_64_BLOCK3_SIZE, CRC32C_X86_64_SKIP[3]);
ptr += 3 * CRC32C_X86_64_BLOCK3_SIZE;
size -= 3 * CRC32C_X86_64_BLOCK3_SIZE;
}
while (size >= 3 * CRC32C_X86_64_BLOCK4_SIZE) {
crc64 = crc32c_x86_64_3lane((uint32_t)crc64, ptr, CRC32C_X86_64_BLOCK4_SIZE, CRC32C_X86_64_SKIP[4]);
ptr += 3 * CRC32C_X86_64_BLOCK4_SIZE;
size -= 3 * CRC32C_X86_64_BLOCK4_SIZE;
}
while (size >= 3 * CRC32C_X86_64_BLOCK5_SIZE) {
crc64 = crc32c_x86_64_3lane((uint32_t)crc64, ptr, CRC32C_X86_64_BLOCK5_SIZE, CRC32C_X86_64_SKIP[5]);
ptr += 3 * CRC32C_X86_64_BLOCK5_SIZE;
size -= 3 * CRC32C_X86_64_BLOCK5_SIZE;
}
}
while (size >= 16) {
asm volatile ("crc32q %1, %0\n" : "+r" (crc64) : "m" (*(const uint64_t*)ptr));
asm volatile ("crc32q %1, %0\n" : "+r" (crc64) : "m" (*(const uint64_t*)(ptr + 8)));
ptr += 16;
size -= 16;
}
if (size >= 8) {
asm volatile ("crc32q %1, %0\n" : "+r" (crc64) : "m" (*(const uint64_t*)ptr));
ptr += 8;
size -= 8;
}
crc = (uint32_t)crc64;
#else
while (size >= 16) {
asm volatile ("crc32l %1, %0\n" : "+r" (crc) : "m" (*(const uint32_t*)ptr));
asm volatile ("crc32l %1, %0\n" : "+r" (crc) : "m" (*(const uint32_t*)(ptr + 4)));
asm volatile ("crc32l %1, %0\n" : "+r" (crc) : "m" (*(const uint32_t*)(ptr + 8)));
asm volatile ("crc32l %1, %0\n" : "+r" (crc) : "m" (*(const uint32_t*)(ptr + 12)));
ptr += 16;
size -= 16;
}
if (size >= 8) {
asm volatile ("crc32l %1, %0\n" : "+r" (crc) : "m" (*(const uint32_t*)ptr));
asm volatile ("crc32l %1, %0\n" : "+r" (crc) : "m" (*(const uint32_t*)(ptr + 4)));
ptr += 8;
size -= 8;
}
#endif
if (size >= 4) {
asm volatile ("crc32l %1, %0\n" : "+r" (crc) : "m" (*(const uint32_t*)ptr));
ptr += 4;
size -= 4;
}
if (size >= 2) {
asm volatile ("crc32w %1, %0\n" : "+r" (crc) : "m" (*(const uint16_t*)ptr));
ptr += 2;
size -= 2;
}
if (size) {
asm volatile ("crc32b %1, %0\n" : "+r" (crc) : "m" (*ptr));
}
return crc;
}
#endif
#if CONFIG_ARM_CRC
static __always_inline uint32_t crc32c_arm64_skip(uint32_t crc, const uint32_t table[8][16])
{
return table[0][crc & 0xf]
^ table[1][(crc >> 4) & 0xf]
^ table[2][(crc >> 8) & 0xf]
^ table[3][(crc >> 12) & 0xf]
^ table[4][(crc >> 16) & 0xf]
^ table[5][(crc >> 20) & 0xf]
^ table[6][(crc >> 24) & 0xf]
^ table[7][crc >> 28];
}
static __always_inline uint32_t crc32c_arm64_2lane(uint32_t crc, const unsigned char* ptr, size_t lane_size, const uint32_t table[8][16])
{
const unsigned char* ptr0 = ptr;
const unsigned char* ptr1 = ptr + lane_size;
const unsigned char* end = ptr1;
uint32_t crc0 = crc;
uint32_t crc1 = 0;
/*
* Keep two dependency chains in flight to hide the CRC32 latency.
*/
while (ptr0 < end) {
uint64_t val00;
uint64_t val01;
uint64_t val02;
uint64_t val03;
uint64_t val10;
uint64_t val11;
uint64_t val12;
uint64_t val13;
__builtin_memcpy(&val00, ptr0, 8);
__builtin_memcpy(&val10, ptr1, 8);
__builtin_memcpy(&val01, ptr0 + 8, 8);
__builtin_memcpy(&val11, ptr1 + 8, 8);
__builtin_memcpy(&val02, ptr0 + 16, 8);
__builtin_memcpy(&val12, ptr1 + 16, 8);
__builtin_memcpy(&val03, ptr0 + 24, 8);
__builtin_memcpy(&val13, ptr1 + 24, 8);
asm volatile ("crc32cx %w0, %w0, %x1\n" : "+r" (crc0) : "r" (val00));
asm volatile ("crc32cx %w0, %w0, %x1\n" : "+r" (crc1) : "r" (val10));
asm volatile ("crc32cx %w0, %w0, %x1\n" : "+r" (crc0) : "r" (val01));
asm volatile ("crc32cx %w0, %w0, %x1\n" : "+r" (crc1) : "r" (val11));
asm volatile ("crc32cx %w0, %w0, %x1\n" : "+r" (crc0) : "r" (val02));
asm volatile ("crc32cx %w0, %w0, %x1\n" : "+r" (crc1) : "r" (val12));
asm volatile ("crc32cx %w0, %w0, %x1\n" : "+r" (crc0) : "r" (val03));
asm volatile ("crc32cx %w0, %w0, %x1\n" : "+r" (crc1) : "r" (val13));
ptr0 += 32;
ptr1 += 32;
}
return crc32c_arm64_skip(crc0, table) ^ crc1;
}
static __always_inline uint32_t crc32c_arm64_plain(uint32_t crc, const unsigned char* ptr, size_t size)
{
if (size >= 2 * CRC32C_ARM64_BLOCK5_SIZE) {
while (size >= 2 * CRC32C_ARM64_BLOCK0_SIZE) {
crc = crc32c_arm64_2lane(crc, ptr, CRC32C_ARM64_BLOCK0_SIZE, CRC32C_ARM64_SKIP[0]);
ptr += 2 * CRC32C_ARM64_BLOCK0_SIZE;
size -= 2 * CRC32C_ARM64_BLOCK0_SIZE;
}
while (size >= 2 * CRC32C_ARM64_BLOCK1_SIZE) {
crc = crc32c_arm64_2lane(crc, ptr, CRC32C_ARM64_BLOCK1_SIZE, CRC32C_ARM64_SKIP[1]);
ptr += 2 * CRC32C_ARM64_BLOCK1_SIZE;
size -= 2 * CRC32C_ARM64_BLOCK1_SIZE;
}
while (size >= 2 * CRC32C_ARM64_BLOCK2_SIZE) {
crc = crc32c_arm64_2lane(crc, ptr, CRC32C_ARM64_BLOCK2_SIZE, CRC32C_ARM64_SKIP[2]);
ptr += 2 * CRC32C_ARM64_BLOCK2_SIZE;
size -= 2 * CRC32C_ARM64_BLOCK2_SIZE;
}
while (size >= 2 * CRC32C_ARM64_BLOCK3_SIZE) {
crc = crc32c_arm64_2lane(crc, ptr, CRC32C_ARM64_BLOCK3_SIZE, CRC32C_ARM64_SKIP[3]);
ptr += 2 * CRC32C_ARM64_BLOCK3_SIZE;
size -= 2 * CRC32C_ARM64_BLOCK3_SIZE;
}
while (size >= 2 * CRC32C_ARM64_BLOCK4_SIZE) {
crc = crc32c_arm64_2lane(crc, ptr, CRC32C_ARM64_BLOCK4_SIZE, CRC32C_ARM64_SKIP[4]);
ptr += 2 * CRC32C_ARM64_BLOCK4_SIZE;
size -= 2 * CRC32C_ARM64_BLOCK4_SIZE;
}
while (size >= 2 * CRC32C_ARM64_BLOCK5_SIZE) {
crc = crc32c_arm64_2lane(crc, ptr, CRC32C_ARM64_BLOCK5_SIZE, CRC32C_ARM64_SKIP[5]);
ptr += 2 * CRC32C_ARM64_BLOCK5_SIZE;
size -= 2 * CRC32C_ARM64_BLOCK5_SIZE;
}
}
while (size >= 8) {
uint64_t val;
__builtin_memcpy(&val, ptr, 8);
asm volatile ("crc32cx %w0, %w0, %x1\n" : "+r" (crc) : "r" (val));
ptr += 8;
size -= 8;
}
if (size >= 4) {
uint32_t val;
__builtin_memcpy(&val, ptr, 4);
asm volatile ("crc32cw %w0, %w0, %w1\n" : "+r" (crc) : "r" (val));
ptr += 4;
size -= 4;
}
while (size) {
asm volatile ("crc32cb %w0, %w0, %w1\n" : "+r" (crc) : "r" (*ptr));
++ptr;
--size;
}
return crc;
}
#endif
/**
* Compute the CRC-32 (Castagnoli)
*/
extern uint32_t (*crc32c)(uint32_t crc, const unsigned char* ptr, size_t size);
/**
* Internal entry points for testing.
*/
uint32_t crc32c_gen(uint32_t crc, const unsigned char* ptr, size_t size);
uint32_t crc32c_x86(uint32_t crc, const unsigned char* ptr, size_t size);
uint32_t crc32c_arm64(uint32_t crc, const unsigned char* ptr, size_t size);
/**
* Initialize the CRC-32 (Castagnoli) support.
*/
void crc32c_init(void);
/****************************************************************************/
/* hash */
/**
* Size of the hash.
*/
#define HASH_MAX 16
/**
* Hash kinds.
*/
#define HASH_UNDEFINED 0
#define HASH_MURMUR3 1
#define HASH_SPOOKY2 2
#define HASH_MUSEAIR 3
/**
* Return the hash that is expected to be the fastest in this architecture
*/
unsigned membesthash(void);
/**
* Return the name of the hash
*/
const char* memhashname(unsigned kind);
/**
* Compute the HASH of a memory buffer.
* Seed is a 128 bit vector.
*
* This is the raw hash primitive. It hashes exactly size bytes and does not
* apply SnapRAID block semantics.
*/
void memhash(unsigned kind, const unsigned char* seed, void* digest, const void* src, size_t size);
/**
* Compute the hash of a SnapRAID data block.
*
* logical_size is the number of bytes logically belonging to the file.
* block_size is the complete zero-padded RAID block size.
*
* Legacy hashes preserve their historical semantics and hash only
* logical_size bytes.
*
* MuseAir hashes the complete canonical RAID block, including the zero
* padding up to block_size.
*
* The caller must guarantee that logical_size <= block_size and, when
* logical_size < block_size, src[logical_size .. block_size-1] == 0.
*/
void memhash_block(unsigned kind, const unsigned char* seed, void* digest, const void* src, size_t logical_size, size_t block_size);
/**
* Return !=0 if the hash kind operates on the complete canonical RAID block.
*
* Legacy hashes (Murmur3, Spooky2) preserve historical semantics and hash
* only the logical file bytes.
* Modern hashes (MuseAir) hash the complete zero-padded RAID block up to
* block_size.
*/
static inline int memhash_is_block(unsigned kind)
{
return kind == HASH_MUSEAIR;
}
/**
* Return the hash name.
*/
const char* hash_config_name(unsigned kind);
/**
* Count the number of different bits in the two buffers.
*/
unsigned memdiff(const unsigned char* data1, const unsigned char* data2, size_t size);
/**
* Unit test
*/
int util_selftest(void);
/****************************************************************************/
/* lock */
/**
* Create and locks the lock file.
* Return -1 on error, otherwise it's the file handle to pass to lock_unlock().
*/
int lock_lock(const char* file);
/**
* Unlock the lock file.
* Return -1 on error.
*/
int lock_unlock(int f);
/****************************************************************************/
/* bitvect */
typedef unsigned char bit_vect_t;
#define BIT_VECT_SIZE (sizeof(bit_vect_t) * 8)
static inline size_t bit_vect_size(size_t max)
{
return (max / BIT_VECT_SIZE) + ((max % BIT_VECT_SIZE) != 0);
}
static inline void bit_vect_set(bit_vect_t* bit_vect, size_t off)
{
bit_vect_t mask = 1 << (off % BIT_VECT_SIZE);
bit_vect[off / BIT_VECT_SIZE] |= mask;
}
static inline void bit_vect_clear(bit_vect_t* bit_vect, size_t off)
{
bit_vect_t mask = 1 << (off % BIT_VECT_SIZE);
bit_vect[off / BIT_VECT_SIZE] &= ~mask;
}
static inline int bit_vect_test(bit_vect_t* bit_vect, size_t off)
{
bit_vect_t mask = 1 << (off % BIT_VECT_SIZE);
return (bit_vect[off / BIT_VECT_SIZE] & mask) != 0;
}
/****************************************************************************/
/* muldiv */
unsigned muldiv(uint64_t v, uint64_t mul, uint64_t div);
unsigned muldiv_upper(uint64_t v, uint64_t mul, uint64_t div);
#endif

View file

@ -1,112 +1,46 @@
dnl Process this file with autoconf to produce a configure script. dnl Process this file with autoconf to produce a configure script.
AC_PREREQ([2.70]) AC_PREREQ([2.65])
dnl Get version number from git AC_INIT([snapraid], [4.4], [], [], [http://snapraid.sourceforge.net])
m4_define([git_revision], m4_esyscmd_s([./autover.sh])) AM_INIT_AUTOMAKE([foreign no-dependencies -Wall])
AC_INIT([SnapRAID CLI],[git_revision],[],[snapraid],[https://www.snapraid.it]) AC_CONFIG_SRCDIR([snapraid.c])
AC_CONFIG_HEADER([config.h])
AC_CANONICAL_HOST AC_CANONICAL_HOST
AC_CANONICAL_BUILD
AC_CANONICAL_TARGET
AM_INIT_AUTOMAKE([foreign no-dependencies subdir-objects])
AC_CONFIG_SRCDIR([os/os.h])
AC_CONFIG_HEADERS([config.h])
dnl Enables as many system-specific extensions as reasonably possible
AC_USE_SYSTEM_EXTENSIONS
dnl Macro directory
AC_CONFIG_MACRO_DIRS([m4])
dnl Checks for programs. dnl Checks for programs.
AC_PROG_CC AC_PROG_CC
AC_USE_SYSTEM_EXTENSIONS
AC_CHECK_PROG([VALGRIND],[valgrind],[valgrind],[]) AC_CHECK_PROG([VALGRIND],[valgrind],[valgrind],[])
AC_CHECK_PROG([WINE],[wine64],[wine64],[]) AC_CHECK_PROG([WINE],[wine],[wine],[])
AC_CHECK_PROG([SDE],[sde64],[sde64],[])
AC_CHECK_PROG([ADVD2],[advd2],[advd2],[]) AC_CHECK_PROG([ADVD2],[advd2],[advd2],[])
AM_CONDITIONAL(HAVE_ADVD2, [test x"$ADVD2" != x]) AM_CONDITIONAL(HAVE_ADVD2, [test x"$ADVD2" != x])
# Compile a quick test program using a syntax unique to C99 and newer dnl Checks for libraries.
AC_MSG_CHECKING([if compiler supports C99 or newer features])
AC_COMPILE_IFELSE([
AC_LANG_PROGRAM([[]], [[
int x = 0;
x++;
int y = x;
int array[y];
]])
], [
AC_MSG_RESULT([yes])
], [
AC_MSG_RESULT([no])
AC_MSG_ERROR([A C99-compliant compiler or newer is required to build this package.])
])
# Check if we are targeting Windows
is_windows=no
AS_CASE([$host_os], [mingw*|msys*|cygwin*], [is_windows=yes])
AM_CONDITIONAL([HOST_WINDOWS], [test "x$is_windows" = "xyes"])
# Check for Windows-specific tools only if on Windows
if test "x$is_windows" = "xyes"; then
AC_CHECK_TOOL([WINDMC], [windmc])
AC_CHECK_TOOL([WINDRES], [windres])
fi
dnl Options to improve stacktrace (some disabled as no crash reported by years)
AX_CHECK_COMPILE_FLAG([-fno-omit-frame-pointer], CFLAGS="$CFLAGS -fno-omit-frame-pointer", [])
# AX_CHECK_COMPILE_FLAG([-fno-inline-functions-called-once], CFLAGS="$CFLAGS -fno-inline-functions-called-once", [])
# AX_CHECK_COMPILE_FLAG([-fno-inline-small-functions], CFLAGS="$CFLAGS -fno-inline-small-functions", [])
# AX_CHECK_COMPILE_FLAG([-fno-optimize-sibling-calls], CFLAGS="$CFLAGS -fno-optimize-sibling-calls", [])
AX_CHECK_COMPILE_FLAG([-rdynamic], CFLAGS="$CFLAGS -rdynamic", [])
# This is the new default for gcc 10
AX_CHECK_COMPILE_FLAG([-fno-common], CFLAGS="$CFLAGS -fno-common", [])
dnl Checks for system.
AC_SYS_LARGEFILE AC_SYS_LARGEFILE
dnl Checks for architecture
AC_C_BIGENDIAN
dnl Checks for header files. dnl Checks for header files.
AC_HEADER_ASSERT AC_HEADER_ASSERT
AC_HEADER_SYS_WAIT AC_HEADER_STDC
AC_CHECK_HEADERS([dirent.h stdint.h inttypes.h unistd.h math.h execinfo.h strings.h getopt.h syslog.h grp.h pwd.h io.h alloca.h]) AC_HEADER_DIRENT
AC_CHECK_HEADERS([sys/file.h sys/sysctl.h sys/ioctl.h sys/time.h sys/types.h sys/mkdev.h sys/sysmacros.h sys/stat.h sys/prctl.h sys/sysinfo.h sys/utsname.h]) AC_HEADER_TIME
AC_CHECK_HEADERS([linux/fs.h linux/btrfs.h linux/fiemap.h]) AC_CHECK_HEADERS([fcntl.h stddef.h stdint.h stdlib.h string.h limits.h])
AC_CHECK_HEADERS([unistd.h getopt.h fnmatch.h io.h inttypes.h byteswap.h])
# Check for the close_range(...,CLOSE_RANGE_CLOEXEC) AC_CHECK_HEADERS([sys/time.h sys/file.h sys/ioctl.h sys/vfs.h sys/statfs.h sys/param.h sys/mount.h])
AC_CHECK_HEADERS([linux/close_range.h]) AC_CHECK_HEADERS([linux/fiemap.h linux/fs.h])
AC_CHECK_FUNCS([close_range])
AC_MSG_CHECKING([for CLOSE_RANGE_CLOEXEC])
AC_COMPILE_IFELSE([
AC_LANG_PROGRAM([[
#ifdef HAVE_LINUX_CLOSE_RANGE_H
#include <linux/close_range.h>
#endif
#include <unistd.h>
]], [[
unsigned int flags = CLOSE_RANGE_CLOEXEC;
]])
], [
AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_CLOSE_RANGE_CLOEXEC], [1], [Define if CLOSE_RANGE_CLOEXEC is available])
], [
AC_MSG_RESULT([no])
])
dnl Checks for typedefs, structures, and compiler characteristics. dnl Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_C_INLINE AC_C_INLINE
AC_C_RESTRICT AC_C_RESTRICT
AC_C_VOLATILE AC_C_VOLATILE
AC_TYPE_SIZE_T AC_TYPE_SIZE_T
AC_TYPE_OFF_T AC_TYPE_OFF_T
AC_TYPE_SIZE_T
AC_TYPE_SSIZE_T AC_TYPE_SSIZE_T
AC_TYPE_UINT32_T AC_TYPE_UINT32_T
AC_TYPE_UINT64_T AC_TYPE_UINT64_T
AC_TYPE_UINT8_T AC_TYPE_UINT8_T
AC_TYPE_INT8_T AC_TYPE_INT8_T
AC_STRUCT_DIRENT_D_INO AC_CHECK_MEMBERS([struct stat.st_mtim.tv_nsec, struct stat.st_mtimensec, struct stat.st_mtimespec.tv_nsec], [], [], [[
AC_STRUCT_DIRENT_D_TYPE
AC_CHECK_MEMBERS([struct stat.st_nlink, struct stat.st_mtim.tv_nsec, struct stat.st_mtimensec, struct stat.st_mtimespec.tv_nsec], [], [], [[
#if HAVE_SYS_TYPES_H #if HAVE_SYS_TYPES_H
#include <sys/types.h> #include <sys/types.h>
#endif #endif
@ -117,37 +51,6 @@ AC_CHECK_MEMBERS([struct stat.st_nlink, struct stat.st_mtim.tv_nsec, struct stat
#include <unistd.h> #include <unistd.h>
#endif #endif
]]) ]])
dnl Checks for library functions.
AC_CHECK_FUNCS([memset strchr strerror strrchr mkdir gettimeofday strtoul])
AC_CHECK_FUNCS([getopt getopt_long snprintf vsnprintf sigaction])
AC_CHECK_FUNCS([ftruncate fallocate access])
AC_CHECK_FUNCS([fsync posix_fadvise sync_file_range syncfs])
AC_CHECK_FUNCS([getc_unlocked ferror_unlocked])
AC_CHECK_FUNCS([futimes futimens futimesat localtime_r lutimes utimensat])
AC_CHECK_FUNCS([fstatat flock renameat statx])
AC_CHECK_FUNCS([backtrace backtrace_symbols])
AC_SEARCH_LIBS([clock_gettime], [rt])
AC_CHECK_FUNCS([clock_gettime])
AC_CHECK_FUNCS([fexecve pipe2])
AC_SEARCH_LIBS([exp], [m])
AC_CHECK_FUNCS([eaccess faccessat])
dnl Checks for statfs for linux avoiding to include sys/mount.h that is required only in darwin
dnl In glibc since 7eae6a91e9b1670330c9f15730082c91c0b1d570, milestone 2.36, sys/mount.h defines fsconfig_command which conflicts with linux/mount.h
AC_CHECK_HEADERS([sys/vfs.h sys/statfs.h])
AC_CHECK_DECLS([statfs], [], [
AC_CHECK_HEADERS([sys/param.h sys/mount.h])
], [[
#if HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
#if HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
]])
AC_CHECK_FUNCS([statfs])
AC_CHECK_MEMBERS([struct statfs.f_type], [], [], [[ AC_CHECK_MEMBERS([struct statfs.f_type], [], [], [[
#if HAVE_SYS_PARAM_H #if HAVE_SYS_PARAM_H
#include <sys/param.h> #include <sys/param.h>
@ -163,266 +66,69 @@ AC_CHECK_MEMBERS([struct statfs.f_type], [], [], [[
#endif #endif
]]) ]])
AC_CHECK_MEMBERS([struct statfs.f_fstypename], [], [], [[ dnl Checks for library functions.
#if HAVE_SYS_PARAM_H AC_SYS_LARGEFILE
#include <sys/param.h> AC_CHECK_FUNCS([memset strchr strerror strrchr mkdir gettimeofday strtoul])
#endif AC_CHECK_FUNCS([getopt getopt_long snprintf vsnprintf])
#if HAVE_SYS_MOUNT_H AC_CHECK_FUNCS([ftruncate fallocate fsync access posix_fallocate posix_fadvise])
#include <sys/mount.h> AC_CHECK_FUNCS([pread pwrite getc_unlocked ferror_unlocked fnmatch])
#endif AC_CHECK_FUNCS([futimes futimens futimesat fstatat flock statfs])
#if HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
#if HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
]])
dnl Checks for libraries dnl Checks for architecture
AS_IF([test "x$is_windows" = "xyes"], [ AC_C_BIGENDIAN
AC_MSG_NOTICE([Windows native threads support enabled])
], [
AC_CHECK_HEADERS([pthread.h])
AX_PTHREAD([
thread_model="pthreads"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
AC_DEFINE([HAVE_PTHREAD], [1], [Define to 1 if POSIX threads are available])
AC_MSG_NOTICE([POSIX threads support enabled])
], [
AC_MSG_WARN([Single-threaded version])
])
])
dnl Checks for compiler dnl Checks for compiler
AX_CHECK_COMPILE_FLAG([-Wall], CFLAGS="$CFLAGS -Wall", []) AC_CHECK_CC_OPT([-Wall], CFLAGS="$CFLAGS -Wall", [])
AX_CHECK_COMPILE_FLAG([-Wextra], CFLAGS="$CFLAGS -Wextra", []) AC_CHECK_CC_OPT([-Wextra], CFLAGS="$CFLAGS -Wextra", [])
AX_CHECK_COMPILE_FLAG([-Wuninitialized], CFLAGS="$CFLAGS -Wuninitialized", [])
AX_CHECK_COMPILE_FLAG([-Wshadow], CFLAGS="$CFLAGS -Wshadow", [])
AX_CHECK_COMPILE_FLAG([-Wshorten-64-to-32], CFLAGS="$CFLAGS -Wshorten-64-to-32", [])
dnl Disable warning about zero-length-bounds raised by gcc 10 on linux kernel header on the fm_extents field
AX_CHECK_COMPILE_FLAG([-Wno-zero-length-bounds], CFLAGS="$CFLAGS -Wno-zero-length-bounds", [])
dnl Checks for asm
AC_ARG_ENABLE([asm],
AS_HELP_STRING([--disable-asm], [Disable inline assembly]))
AS_IF([test "x$enable_asm" != "xno"], [
AC_DEFINE([HAVE_ASSEMBLY], [1], [Define to 1 if inline assembly should be used.])
])
dnl Optional command prefix used to execute cross-compiled target binaries.
dnl For example:
dnl TARGET_RUNNER="qemu-arm -cpu cortex-a15 -L /usr/arm-linux-gnueabihf"
AC_ARG_VAR([TARGET_RUNNER], [Command prefix used to execute cross-compiled target binaries])
dnl Checks for test environment dnl Checks for test environment
AS_CASE([$host], AS_CASE([$host],
[*-*-mingw*], [*-*-mingw*], [TESTENV="$WINE"],
[ [SYMLINK=1]
TESTENV="$WINE"
FAILENV="$TESTENV"
],
[
POSIX=1
AS_IF([test "x$cross_compiling" = "xyes" && test -n "$TARGET_RUNNER"],
[
TESTENV="$TARGET_RUNNER"
FAILENV="$TESTENV"
AC_MSG_NOTICE([Cross-compiled target runner: $TARGET_RUNNER])
])
]
) )
AM_CONDITIONAL(HAVE_POSIX, [test x"$POSIX" != x]) AM_CONDITIONAL(HAVE_SYMLINK, [test x"$SYMLINK" != x])
AM_CONDITIONAL(CROSS_COMPILING, [test "x$cross_compiling" = "xyes"])
AM_CONDITIONAL(HAVE_DISK_ARBITRATION, [test "$(uname)" = Darwin])
AC_ARG_ENABLE([profiler], AC_ARG_ENABLE([profiler],
[AS_HELP_STRING([--enable-profiler],[enable the use of gprof for code coverage])], [AS_HELP_STRING([--enable-profiler],[enable the use of gprof for code coverage])],
[ [
CFLAGS="-O2 -pg -g -pthread" TESTENV=""
CFLAGS="-O2 -pg -g"
], ],
[]) [])
AC_ARG_ENABLE([coverage], AC_ARG_ENABLE([coverage],
[AS_HELP_STRING([--enable-coverage],[enable the use of gcov for code coverage])], [AS_HELP_STRING([--enable-coverage],[enable the use of gcov for code coverage])],
[ [
CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage -pthread" TESTENV=""
CFLAGS="-O0 -g -fprofile-arcs -ftest-coverage"
], ],
[]) [])
AC_ARG_ENABLE([valgrind], AC_ARG_ENABLE([valgrind],
[AS_HELP_STRING([--enable-valgrind],[enable the use of valgrind in testing])], [AS_HELP_STRING([--enable-valgrind],[enable the use of valgrind in testing])],
[ [
TESTENV="$VALGRIND --leak-check=full --suppressions=valgrind.supp --error-exitcode=1" TESTENV="$VALGRIND --leak-check=full --track-fds=yes --error-exitcode=1"
FAILENV="$VALGRIND --error-exitcode=1"
CFLAGS="$CFLAGS -DCHECKER" CFLAGS="$CFLAGS -DCHECKER"
MEMORY_CHECKER=1
], ],
[]) [])
AC_ARG_ENABLE([sgcheck], AC_ARG_ENABLE([sgcheck],
[AS_HELP_STRING([--enable-sgcheck],[enable the use of sgcheck in testing])], [AS_HELP_STRING([--enable-sgcheck],[enable the use of sgcheck in testing])],
[ [
TESTENV="$VALGRIND --tool=exp-sgcheck --suppressions=valgrind.supp --error-exitcode=1" TESTENV="$VALGRIND --tool=exp-sgcheck --suppressions=sgcheck.supp --error-exitcode=1"
FAILENV="$TESTENV"
CFLAGS="$CFLAGS -DCHECKER" CFLAGS="$CFLAGS -DCHECKER"
MEMORY_CHECKER=1
], ],
[]) [])
AC_ARG_ENABLE([helgrind],
[AS_HELP_STRING([--enable-helgrind],[enable the use of helgrind in testing])],
[
TESTENV="$VALGRIND --tool=helgrind --suppressions=valgrind.supp --fair-sched=try --error-exitcode=1"
FAILENV="$TESTENV"
CFLAGS="$CFLAGS -DCHECKER"
THREAD_CHECKER=1
],
[])
AC_ARG_ENABLE([drd],
[AS_HELP_STRING([--enable-drd],[enable the use of drd in testing])],
[
TESTENV="$VALGRIND --tool=drd --suppressions=valgrind.supp --fair-sched=try --error-exitcode=1"
FAILENV="$TESTENV"
CFLAGS="$CFLAGS -DCHECKER"
THREAD_CHECKER=1
],
[])
AC_ARG_ENABLE([asan],
[AS_HELP_STRING([--enable-asan],[enable the use of AddressSanitizer in testing])],
[
CFLAGS="$CFLAGS -DCHECKER -fsanitize=address"
MEMORY_CHECKER=1
],
[])
AC_ARG_ENABLE([msan],
[AS_HELP_STRING([--enable-msan],[enable the use of MemorySanitizer in testing])],
[
CFLAGS="$CFLAGS -DCHECKER -fsanitize=memory"
MEMORY_CHECKER=1
],
[])
AC_ARG_ENABLE([ubsan],
[AS_HELP_STRING([--enable-ubsan],[enable the use of UndefinedBehaviourSanitizer in testing])],
[
CFLAGS="$CFLAGS -DCHECKER -fsanitize=undefined -fno-sanitize=function"
MEMORY_CHECKER=1
],
[])
AC_ARG_ENABLE([tsan],
[AS_HELP_STRING([--enable-tsan],[enable the use of ThreadSanitizer in testing])],
[
CFLAGS="$CFLAGS -DCHECKER -fsanitize=thread"
dnl Use MEMORY_CHECKER instead of THREAD_CHECKER to run the full and long test
MEMORY_CHECKER=1
],
[])
AM_CONDITIONAL(HAVE_MEMORY_CHECKER, [test x"$MEMORY_CHECKER" != x])
AM_CONDITIONAL(HAVE_THREAD_CHECKER, [test x"$THREAD_CHECKER" != x])
AC_ARG_ENABLE([sde],
[AS_HELP_STRING([--enable-sde],[enable the use of SDE emulator in testing])],
dnl p4p -> Pentium4 Prescott with SSE2
dnl mrm -> Merom with SSSE3
dnl nhm -> Nehalem with SSE4.2
dnl hsw -> Haswell with AVX2
dnl knl -> Knights Landing with AVX512F
dnl skx -> Skylake Xeon with AVX512BW
[
TESTENV_SSE2="$SDE -chip-check-exe-only -p4p --"
TESTENV_SSSE3="$SDE -chip-check-exe-only -mrm --"
TESTENV_SSE42="$SDE -nhm --"
TESTENV_AVX2="$SDE -hsw --"
TESTENV_AVX512="$SDE -skx --"
EMULATOR=1
# Target CPU compatible with P4 Prescott
CFLAGS="$CFLAGS -march=athlon64"
],
[])
AM_CONDITIONAL(HAVE_EMULATOR, [test x"$EMULATOR" != x])
AC_ARG_ENABLE([debug], AC_ARG_ENABLE([debug],
[AS_HELP_STRING([--enable-debug],[enable debugging])], [AS_HELP_STRING([--enable-debug],[enable debugging])],
[ [
CFLAGS="-Og -g -pthread -Wall -Wextra" TESTENV=""
AX_CHECK_COMPILE_FLAG([-rdynamic], CFLAGS="$CFLAGS -rdynamic", []) CFLAGS="-O0 -g -Wall -Wextra"
], ],
[]) [])
AC_ARG_ENABLE([warning-as-error],
[AS_HELP_STRING([--enable-warning-as-error],[stop build on warnings])],
[
AX_CHECK_COMPILE_FLAG([-Werror], CFLAGS="$CFLAGS -Werror", [])
dnl This avoid the Darwin error: clang: error: argument unused during compilation: '-pthread'
dnl See: https://llvm.org/bugs/show_bug.cgi?id=7798
AX_CHECK_COMPILE_FLAG([-Wno-error=unused-command-line-argument], CFLAGS="$CFLAGS -Wno-error=unused-command-line-argument", [])
],
[])
AC_ARG_ENABLE([warning],
[AS_HELP_STRING([--enable-warning],[enable extra warning])],
[
AX_CHECK_COMPILE_FLAG([-Wpointer-arith], CFLAGS="$CFLAGS -Wpointer-arith", [])
AX_CHECK_COMPILE_FLAG([-Wcast-qual], CFLAGS="$CFLAGS -Wcast-qual", [])
AX_CHECK_COMPILE_FLAG([-Wunused], CFLAGS="$CFLAGS -Wunused", [])
AX_CHECK_COMPILE_FLAG([-Wunreachable-code], CFLAGS="$CFLAGS -Wunreachable-code", [])
AX_CHECK_COMPILE_FLAG([-Wpadded], CFLAGS="$CFLAGS -Wpadded", [])
AX_CHECK_COMPILE_FLAG([-Weverything], CFLAGS="$CFLAGS -Weverything", [])
],
[])
# WITH_TOOL(NAME, BINARY, DESCRIPTION)
# Adds --with-NAME=PATH option. Defines NAME_PATH if given.
AC_DEFUN([WITH_TOOL], [
AC_ARG_WITH([$1],
[AS_HELP_STRING([--with-$1=PATH],
[absolute path to the $2 executable ($3)])],
[
AS_CASE([$withval],
[/*], [],
[AC_MSG_ERROR([--with-$1 requires an absolute path (got '$withval')])])
AS_IF([test ! -x "$withval"],
[AC_MSG_WARN([$2 not found or not executable at '$withval'])])
AC_DEFINE_UNQUOTED(m4_toupper([$1_PATH]), ["$withval"],
[Absolute path to $2, set at configure time.])
AC_MSG_NOTICE([$2: $withval])
],
[
AC_MSG_NOTICE([$2: use runtime discovery])
])
])
WITH_TOOL([smartctl], [smartctl], [S.M.A.R.T. monitoring])
WITH_TOOL([zfs], [zfs], [ZFS pool management])
WITH_TOOL([zpool], [zpool], [ZFS pool status])
WITH_TOOL([bcachefs], [bcachefs], [Bcachefs management])
AC_ARG_VAR([TESTENV], [Test environment]) AC_ARG_VAR([TESTENV], [Test environment])
AC_ARG_VAR([FAILENV], [Test environment for failing tests])
AC_ARG_VAR([TESTENV_SSE2], [Test environment for SSE2])
AC_ARG_VAR([TESTENV_SSSE3], [Test environment for SSSE3])
AC_ARG_VAR([TESTENV_SSE42], [Test environment for SSE42])
AC_ARG_VAR([TESTENV_AVX2], [Test environment for AVX2])
AC_ARG_VAR([TESTENV_AVX512], [Test environment for AVX512])
AC_CONFIG_FILES([Makefile]) AC_CONFIG_FILES([Makefile])
AC_CONFIG_FILES([pkg/snapraid.info pkg/control pkg/snapraid.spec pkg/.PKGINFO pkg/PKGBUILD pkg/.SRCINFO])
AC_CONFIG_FILES([makeslackware.sh], [chmod a+x makeslackware.sh])
AC_CONFIG_FILES([makeslackdist.sh], [chmod a+x makeslackdist.sh])
AC_CONFIG_FILES([pkg/snapraid.SlackBuild], [chmod a+x pkg/snapraid.SlackBuild])
AC_CONFIG_FILES([makedeb.sh], [chmod a+x makedeb.sh])
AC_CONFIG_FILES([makerpm.sh], [chmod a+x makerpm.sh])
AC_CONFIG_FILES([makearch.sh], [chmod a+x makearch.sh])
AC_CONFIG_FILES([makearchdist.sh], [chmod a+x makearchdist.sh])
# Ensure object subdirectories exist for out-of-tree builds without depcomp
AC_CONFIG_COMMANDS([mkdir-obj], [$MKDIR_P cmdline raid os tommyds])
AC_OUTPUT AC_OUTPUT

View file

@ -1,3 +0,0 @@
DIR=$(dirname "$0")
"$DIR/configure" CC=/usr/libexec/ccc-analyzer

View file

@ -1,2 +1,3 @@
DIR=$(dirname "$0") ./configure --host=x86_64-w64-mingw32 --build=`./config.guess` $@
"$DIR/configure" --host=x86_64-w64-mingw32.static --build=$("$DIR/config.guess") "$@"

View file

@ -1,4 +1,2 @@
DIR=$(dirname "$0") ./configure --host=i686-pc-mingw32 --build=`./config.guess` $@
"$DIR/configure" --host=i686-w64-mingw32.static --build=$("$DIR/config.guess") "$@"

280
cpu.h Normal file
View file

@ -0,0 +1,280 @@
/*
* Copyright (C) 2011,2013 Andrea Mazzoleni
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CPU_H
#define __CPU_H
#if defined(__i386__) || defined(__x86_64__)
static inline void cpuid(uint32_t func, uint32_t* reg)
{
asm volatile(
#if defined(__i386__) && defined(__PIC__)
/* allow compilation in PIC mode saving ebx */
"xchgl %%ebx, %1\n"
"cpuid\n"
"xchgl %%ebx, %1\n"
: "=a" (reg[0]), "=r" (reg[1]), "=c" (reg[2]), "=d" (reg[3])
: "0" (func)
#else
"cpuid\n"
: "=a" (reg[0]), "=b" (reg[1]), "=c" (reg[2]), "=d" (reg[3])
: "0" (func)
#endif
);
}
#define CPU_VENDOR_MAX 13
static inline void cpu_info(char* vendor, unsigned* family, unsigned* model)
{
uint32_t reg[4];
unsigned f, ef, m, em;
cpuid(0, reg);
((uint32_t*)vendor)[0] = reg[1];
((uint32_t*)vendor)[1] = reg[3];
((uint32_t*)vendor)[2] = reg[2];
vendor[12] = 0;
cpuid(1, reg);
f = (reg[0] >> 8) & 0xF;
ef = (reg[0] >> 20) & 0xFF;
m = (reg[0] >> 4) & 0xF;
em = (reg[0] >> 16) & 0xF;
if (strcmp(vendor, "AuthenticAMD") == 0) {
if (f < 15) {
*family = f;
*model = m;
} else {
*family = f + ef;
*model = m + (em << 4);
}
} else {
*family = f + ef;
*model = m + (em << 4);
}
}
static inline int cpu_has_mmx(void)
{
uint32_t reg[4];
cpuid(1, reg);
return (reg[3] >> 23) & 1;
}
static inline int cpu_has_sse2(void)
{
uint32_t reg[4];
cpuid(1, reg);
return (reg[3] >> 26) & 1;
}
static inline int cpu_has_sse42(void)
{
uint32_t reg[4];
cpuid(1, reg);
return (reg[2] >> 20) & 1;
}
/**
* Check if the processor has a slow MULT implementation.
* If yes, it's better to use a hash not based on multiplication.
*/
static inline int cpu_has_slowmult(void)
{
char vendor[CPU_VENDOR_MAX];
unsigned family;
unsigned model;
cpu_info(vendor, &family, &model);
if (strcmp(vendor, "GenuineIntel") == 0) {
/* Intel(R) Atom(TM) CPU D525 @ 1.80GHz (info from user)
* Compiler gcc 4.7.2
* CPU GenuineIntel, family 6, model 28, flags mmx sse2 slowmult
* Memory is little-endian 64-bit
* Speed test with 8 disk and 262144 buffer size...
* memset0 1849 [MB/s]
* HASH Murmur3 378 [MB/s]
* HASH Spooky2 3413 [MB/s]
* RAID5 int32x2 707 [MB/s]
* RAID5 mmxx2 1264 [MB/s]
* RAID5 mmxx4 1910 [MB/s]
* RAID5 sse2x2 2204 [MB/s]
* RAID5 sse2x4 2980 [MB/s]
* RAID6 int32x2 296 [MB/s]
* RAID6 mmxx2 543 [MB/s]
* RAID6 sse2x2 1068 [MB/s]
* RAID6 sse2x4 1601 [MB/s]
*/
if (family == 6 && model == 28)
return 1;
}
return 0;
}
/* other cases */
/* Intel(R) Core(TM) i7-3740QM CPU @ 2.70GHz
* Compiler gcc 4.7.3
* CPU GenuineIntel, family 6, model 58, flags mmx sse2
* Memory is little-endian 32-bit
* memset0 34685 [MB/s]
* Murmur3 4170 [MB/s]
* Spooky2 2599 [MB/s]
* RAID5 int32x2 8919 [MB/s]
* RAID5 mmxx2 17170 [MB/s]
* RAID5 sse2x2 27478 [MB/s]
* RAID6 int32x2 1953 [MB/s]
* RAID6 mmxx2 7560 [MB/s]
* RAID6 sse2x2 13930 [MB/s]
*/
/* Intel(R) Core(TM) i7-3740QM CPU @ 2.70GHz
* Compiler gcc 4.7.3
* CPU GenuineIntel, family 6, model 58, flags mmx sse2
* Memory is little-endian 64-bit
* memset0 26164 [MB/s]
* Murmur3 4469 [MB/s]
* Spooky2 12834 [MB/s]
* RAID5 int32x2 10775 [MB/s]
* RAID5 mmxx2 19644 [MB/s]
* RAID5 sse2x2 29168 [MB/s]
* RAID6 int32x2 3288 [MB/s]
* RAID6 mmxx2 8374 [MB/s]
* RAID6 sse2x2 15547 [MB/s]
*/
/* Intel(R) Core(TM) i5 CPU 650 @ 3.20GHz
* Compiler gcc 4.7.1
* CPU GenuineIntel, family 6, model 37, flags mmx sse2
* Memory is little-endian 32-bit
* memset0 25468 [MB/s]
* Murmur3 3357 [MB/s]
* Spooky2 1861 [MB/s]
* RAID5 int32x2 5043 [MB/s]
* RAID5 mmxx2 9864 [MB/s]
* RAID5 sse2x2 16896 [MB/s]
* RAID6 int32x2 1100 [MB/s]
* RAID6 mmxx2 5056 [MB/s]
* RAID6 sse2x2 8726 [MB/s]
*/
/* AMD Athlon(tm) 64 X2 Dual Core Processor 3600+ 1913.377 MHz
* Compiler gcc 4.7.3
* CPU AuthenticAMD, family 15, model 107, flags mmx sse2
* Memory is little-endian 32-bit
* memset 2414 [MB/s]
* Murmur3 1213 [MB/s]
* Spooky2 947 [MB/s]
* RAID5 int32x2 532 [MB/s]
* RAID5 mmxx2 1121 [MB/s]
* RAID5 sse2x2 2061 [MB/s]
* RAID6 int32x2 280 [MB/s]
* RAID6 mmxx2 632 [MB/s]
* RAID6 sse2x2 909 [MB/s]
*/
/* ARM Feroceon 88FR131 rev 1 (v5l)
* Compiler gcc 4.7.2
* CPU is not a x86/x64
* Memory is little-endian 32-bit
* memset 763 [MB/s]
* Murmur3 237 [MB/s]
* Spooky2 216 [MB/s]
* RAID5 int32x2 233 [MB/s]
* RAID6 int32x2 103 [MB/s]
*/
/* Intel(R) Xeon(R) CPU E3-1270 V2 @ 3.50GHz $
* Compiler gcc 4.8.1
* CPU GenuineIntel, family 6, model 58, flags mmx sse2
* Memory is little-endian 64-bit
* memset 27842 [MB/s]
* Murmur3 4884 [MB/s]
* Spooky2 14039 [MB/s]
* RAID5 int32x2 11038 [MB/s]
* RAID5 mmxx2 20055 [MB/s]
* RAID5 sse2x2 30703 [MB/s]
* RAID6 int32x2 3267 [MB/s]
* RAID6 mmxx2 8883 [MB/s]
* RAID6 sse2x2 16433 [MB/s]
*/
/* Bobcat/Zacade (info from x264 -> full family 20)
* AMD E-350 Processor (info from user)
* Compiler gcc 4.7.3
* CPU AuthenticAMD, family 20, model 1, flags mmx sse2
* Memory is little-endian 64-bit
* memset 2137 [MB/s]
* Murmur3 1140 [MB/s]
* Spooky2 2326 [MB/s]
* RAID5 int32x2 1853 [MB/s]
* RAID5 mmxx2 2019 [MB/s]
* RAID5 sse2x2 2908 [MB/s]
* RAID6 int32x2 884 [MB/s]
* RAID6 mmxx2 1502 [MB/s]
* RAID6 sse2x2 1168 [MB/s] (slow version with prefetchnta)
*/
/* AMD Turion(tm) II Neo N40L Dual-Core Processor (info from user)
* Compiler gcc 4.7.1
* CPU AuthenticAMD, family 16, model 6, flags mmx sse2
* Memory is little-endian 64-bit
* memset 4910 [MB/s]
* Murmur3 1160 [MB/s]
* Spooky2 3994 [MB/s]
* RAID5 int32x2 530 [MB/s]
* RAID5 mmxx2 1114 [MB/s]
* RAID5 sse2x1 2127 [MB/s]
* RAID5 sse2x2 2804 [MB/s]
* RAID6 int32x2 316 [MB/s]
* RAID6 mmxx2 655 [MB/s]
* RAID6 sse2x2 639 [MB/s] (slow version with prefetchnta)
*/
/* AMD Athlon(tm) II X4 620 (info from user)
* Compiler gcc 4.7.3
* CPU AuthenticAMD, family 16, model 5, flags mmx sse2
* Memory is little-endian 64-bit
* memset 2845 [MB/s]
* Murmur3 2262 [MB/s]
* Murmur3x64 3500 [MB/s]
* Spooky2 4362 [MB/s]
* Spooky2x86 4000 [MB/s]
* RAID5 int32x2 1064 [MB/s]
* RAID5 mmxx2 2064 [MB/s]
* RAID5 sse2x2 3289 [MB/s]
* RAID6 int32x2 639 [MB/s]
* RAID6 mmxx2 1325 [MB/s]
* RAID6 sse2x2 915 [MB/s] (slow version with prefetchnta)
*/
#endif
#endif

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

Some files were not shown because too many files have changed in this diff Show more